I have 3 tables A, X, Y. Records of A are defined by pairs of X and Y - in another table AWithXY. I can model A the way I receive list of X or Y in a list like below:
data class AWithXY(
@Embedded val a: A,
@Relation(
parentColumn = BaseColumns.PK,
entityColumn = BaseColumns.PK,
associateBy = Junction(
value = AWithXY::class,
parentColumn = AWithXY.FK_A,
entityColumn = AWithXY.FK_X,
),
entity = X::class,
)
val xList: List<X>,
// Similar relation for Y
)
Another option would be to define an extra table XWithY and use its primary key instead to associate it with A, but is there a way to do it without it? Technically I could have an embedded class:
data class XWithY(
@Embedded val x: X,
@Embedded val y: Y,
)
And write a custom query and join, so there are some alternatives, but I was wondering if there's something that Room provides to achieve it without extra tables or custom queries.
Ideally it would be having a @Relation to a class with 2 or more @Embedded entities, but I suppose it's impossible, because it's technically a relation to 2 different tables.
The issues is similar to this or this (@Relation limitation).
Currently I believe the best that can be done is to have 4 tables A, X and Y and a mapping/associative/reference .... table.
However, trying to use the convenience
@Relationhas issues in that it will always try to get ALL the relations and if not List(Y) within a List(X) then the first Y per X will be used (see demo output)To demonstrate consider the following which includes variations (V1 and V2).
First the 4 tables (
@Entityannotated classes) A, X Y and AXYMAP:-Now the supportive POJO's:-
getXWithYListV2an
@Daoannotated interface, again noting that V2 is the one that does not return incorrect values.To demo an
@Databaseannotated abstract class:-Finally some Activity code to demo by
:-
Demo Result (as per the log):-
As can be seen All three work fine for A1 and A3, the simpler data but only the 3rd (V2) returns the expected values for A2 (1, 3 and 5 Y's as opposed to the xId rather than the yId value).
Even though the underlying query returns the expected data e.g.
Of course you could use
List<Y>in theXWithYclass with an @Relation but that would then incur a subquery of the subquery which is in efficient as the subquery retrieves all the necessary data.Another option would be to try using Maps as is suggested by the link to the Issue.
So you could just have the following POJOs (with the same 4 tables):-
Along with:-
Additional (re comment)
If you use
@Relationthen Room based upon the parameters supplied via the annotation builds it's own subquery to return ALL children(x) of the parent(y). If you are not receiving into a list of children but just a single child then the first child only will be assigned.That is why the output, when using the
XWithY(original) retrieves the same values for Y (no issue if there is only the 1 Y per X hence why A1 in the first two examples appears fine). It is always taking the same single Y from the list of Y's (hence why A2 gets the same values for the first two examples).The 3rd example doesn't use @Relation (
XWithYV2) but instead uses it's own subquery to then build the List of XWithY's. Hence why the third example works (it doesn't rely upon Room convenience handling).No due to
error: Cannot figure out how to read this field from a cursor. private final java.util.List<a.a.so75784594relationships.XWithYV2> xWithYList = null;However, you could use:-
with :-
in which case using :-
Results in:-
Now if you wanted to use the A X and Y all joined then the result would have to be returned using something like:-
And you could then use:-
The issue is then handling the cartesian product which using:-
would result in:-