Is it possible to generate a list of only the distinct objects (from the child entity) using @Embedded and asscociatedBy = Junction() table?
I have several separated entities (EntityActivityLog, EntityComponent, EntityGroup) associated by the linking table (EntityLinkGroupToActivity).
Essentially each ActivityLog has multiple components, which in turn have multiple groups. (it goes on but for the purposes of this question I'll stop there)
At the moment Im working with the simplified data set as follows:
[activityLog1, component1,group1]
[activityLog1, component1,group2]
[activityLog1, component1,group3]
[activityLog1, component2,group1]
[activityLog1, component4,group1]
[activityLog2, component1,group1] etc...
Using the following code I expected a pojo containing a single embedded activity object and a list of unique component entities. Each componentId would be associated with the activityLogId in the linking table.
data class ActivityLogWithComponentList (
@Embedded
val activityLog: EntityLogActivity,
@Relation(
parentColumn = "activityLogId",
entity = EntityComponent::class,
entityColumn = "componentId ",
associateBy = Junction(
EntityLinkGroupToActivity::class,
parentColumn = "activityLogId",
entityColumn = "componentId ",
)
)
val componentList: List<EntityComponent>
){}
However, in the result for the first activityLog there are 9x components.
POJO List Results:
component1, component1, component1, component2, component4...
I can understand the logic with the 'junction' of the linking table containing all the componentIds as does the component entity table. Thus each row of the junction is always fulfilled. However this is not the outcome Im looking for and haven’t seen an alternative to associateBy = junction().
Ideally I am aiming for only the distinct component items in the list: component1, component2, component4
Any suggestions would be appreciated on how to achieve this using this embedded approach.
Additional Notes:
Coding DISTINCT will have no effect as for an @Relation what room does is build run it's own sub query to get ALL children of the parent.
However, with a few extra Dao's this can be achieved:-
First 2 queries (you may have the first already):-
@Query("SELECT * FROM entityactivitylog")
abstract fun getAllActivityLogs(): List<EntityActivityLog>
@Query("SELECT DISTINCT entitycomponent.* " + /*<<<<< ONLY NEED TO GET COMPONENT columns */
"FROM entitylinkgrouptoactivity " +
"JOIN entitycomponent ON entitycomponent.componentId = entitylinkgrouptoactivity.componentId " +
"WHERE activityLogId=:activityLogId")
abstract fun getDistinctComponentsForAnActivity(activityLogId: Long): List<EntityComponent>
Then a function (note that an abstract class has been used for the Dao's as then a function with a body can be utilised). This function masquerades as a query to allow the @Transaction annotation, it is:-
@Query("")
@Transaction
fun getDistinct(): List<ActivityLogWithComponentList> {
val rv: ArrayList<ActivityLogWithComponentList> = ArrayList()
val currentActivityLog: EntityActivityLog
for (a in getAllActivityLogs()) {
rv.add(
ActivityLogWithComponentList(
activityLog = a,
componentList = getDistinctComponentsForAnActivity(a.activityLogId!!)
)
)
}
return rv
}
Using the above along with (run on the main thread for convenience and brevity):-
const val TAG = "DBINFO"
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
val g1ID = dao.insert(EntityGroup(groupName = "Group1"))
val g2ID = dao.insert(EntityGroup(groupName = "Group2"))
val g3ID = dao.insert(EntityGroup(groupName = "Group3"))
val c1ID = dao.insert(EntityComponent(componentName = "Component1"))
val c2ID = dao.insert(EntityComponent(componentName = "Component2"))
val c3ID = dao.insert(EntityComponent(componentName = "Component3"))
val c4ID = dao.insert(EntityComponent(componentName = "Component4"))
val a1ID = dao.insert(EntityActivityLog(activityName = "Activity1"))
val a2ID = dao.insert(EntityActivityLog(activityName = "Activity2"))
dao.insert(EntityLinkGroupToActivity(activityLogId = a1ID, componentId = c1ID, groupId = g1ID))
dao.insert(EntityLinkGroupToActivity(activityLogId = a1ID, componentId = c1ID, groupId = g2ID))
dao.insert(EntityLinkGroupToActivity(activityLogId = a1ID, componentId = c1ID, groupId = g3ID))
dao.insert(EntityLinkGroupToActivity(activityLogId = a1ID, componentId = c2ID, groupId = g1ID))
dao.insert(EntityLinkGroupToActivity(activityLogId = a1ID, componentId = c4ID, groupId = g1ID))
dao.insert(EntityLinkGroupToActivity(activityLogId = a2ID, componentId = c1ID, groupId = g1ID))
for(al: ActivityLogWithComponentList in dao.getOriginal()) {
Log.d(TAG+"RUN1","Activity Log is ${al.activityLog.activityName} it has ${al.componentList.size} components")
for (c: EntityComponent in al.componentList) {
Log.d(TAG,"\tComponent is ${c.componentName}")
}
}
for (al: ActivityLogWithComponentList in dao.getDistinct()) {
Log.d(TAG+"RUN2","Activity Log is ${al.activityLog.activityName} it has ${al.componentList.size} components")
for (c: EntityComponent in al.componentList) {
Log.d(TAG,"\tComponent is ${c.componentName}")
}
}
}
}
The results in the log are:-
Original
2021-12-13 20:13:43.949 D/DBINFORUN1: Activity Log is Activity1 it has 5 components
2021-12-13 20:13:43.949 D/DBINFO: Component is Component1
2021-12-13 20:13:43.949 I/chatty: uid=10145(a.a.so70330069kotlinroomrelationships) identical 1 line
2021-12-13 20:13:43.949 D/DBINFO: Component is Component1
2021-12-13 20:13:43.949 D/DBINFO: Component is Component2
2021-12-13 20:13:43.949 D/DBINFO: Component is Component4
2021-12-13 20:13:43.949 D/DBINFORUN1: Activity Log is Activity2 it has 1 components
2021-12-13 20:13:43.949 D/DBINFO: Component is Component1
Distinct/Unique
2021-12-13 20:13:43.961 D/DBINFORUN2: Activity Log is Activity1 it has 3 components
2021-12-13 20:13:43.961 D/DBINFO: Component is Component1
2021-12-13 20:13:43.961 D/DBINFO: Component is Component2
2021-12-13 20:13:43.961 D/DBINFO: Component is Component4
2021-12-13 20:13:43.961 D/DBINFORUN2: Activity Log is Activity2 it has 1 components
2021-12-13 20:13:43.961 D/DBINFO: Component is Component1