Reputation: 33
I have the following data structure which consist in a list of providers, having products and each product has different types
Provider Class
public class Provider extends RealmObject {
@SerializedName("id")
@PrimaryKey
public int providerId;
public String name;
public RealmList<Product> products;
}
Product Class
public class Product extends RealmObject {
@SerializedName("id")
@PrimaryKey
public int productId;
public String name;
public RealmList<ProductType> types;
}
Product type class
public class ProductType extends RealmObject {
@SerializedName("id")
@PrimaryKey
public int productTypeId;
public String name;
public Packaging packaging; }
Here is a JSON example of what is loaded into realm:
{
"providers": [{
"id": 1,
"name": "PROVIDER_1",
"products": [{
"id": 10,
"name": "Banana",
"types": [{
"id": 101,
"name": "Costa rica",
"packaging": {
"isFree": true,
"value": 0
}
},
{
"id": 102,
"name": "Brasil",
"packaging": {
"isFree": true,
"value": 0
}
}
]
}]
},{
"id": 4,
"name": "PROVIDER_2",
"products": [{
"id": 10,
"name": "Banana",
"types": [{
"id": 103,
"name": "Ecuador Prem",
"packaging": {
"isFree": true,
"value": 0
}
}
]
},
{
"id": 21,
"name": "Apple",
"types": [{
"id": 212,
"name": "Red del",
"packaging": {
"isFree": true,
"value": 0
}
}
]
}]
}
]
}
So, the problem I am having is appear when I try to fetch types of Bananas using the following query
RealmResults<Provider> results = mRealm.where(Provider.class).equalTo("providerId", providerId).findAll();
Product product = results.where().equalTo("providerId", providerId).findFirst().products.where().equalTo("productId", productId).findFirst();
RealmList<ProductType> types = product.types;
the list of Types returned is giving me always the types of the second provider. In current example, I am getting "Ecuador Prem" even if I am requesting provider id 1 which is PROVIDER_1, and that provider must return as types "Costa rica" and "Brasil".
Upvotes: 0
Views: 141
Reputation: 81539
You have either one of two or three problems:
1.) your API returns that the product type
is of id
for Banana
, but you are getting id=10;Banana
both for Provider1 and Provider2, therefore the Banana
that has Provider1
is saved, after which Banana
that has Provider2
with the same ID is saved (and therefore overwriting the original Banana
with Provider1
instead of "merging them" for example).
So instead of directly mapping API responses to RealmObjects, you're supposed to introduce a manually computed composite key, which is most likely a String field that contains both the ProviderID concatenated with the ProductTypeID.
public class Product extends RealmObject {
@PrimaryKey
public String providerWithProductId; // must be set, like "$PROVIDERID_$PRODUCTID"
@Index
public int productId;
public String name;
public RealmList<ProductType> types;
}
I hope this is not a Sync Realm!
2.) You are directly mapping the JSON objects to Realm, possibly out of "convenience", but this deprives you of setting up an optimal schema for your queries.
In reality, "Provider" doesn't seem particularly important beyond that a particular banana belongs to a certain provider; this can be modelled as a field, instead of an object link.
// public class Provider extends RealmObject {
//
// @SerializedName("id")
// @PrimaryKey
// public int providerId;
// public String name;
// public RealmList<Product> products;
//
// }
public class Product extends RealmObject {
@PrimaryKey
public String providerWithProductId; // must be set
@Index
public int productId;
public String productName;
@Index
public int providerId;
public String providerName;
public RealmList<ProductType> productTypes;
}
On top of that, packaging
is just two fields that could easily be merged into ProductType
. And also, if Ecuador Prem
type can belong to multiple products and multiple providers, then it should also have a composite key constructed from all 3 of these IDs!
public class ProductType extends RealmObject {
@PrimaryKey
public String providerWithProductWithProductTypeId; // you must fill this yourself
@Index
public int providerId;
@Index
public int productTypeId;
@Index
public int productId;
public String productTypeName;
//public Packaging packaging;
public boolean packagingIsFree;
public long packagingValue;
}
3.) Once you have that, you could easily rely on either of checking directly for the providerId
also saved into the ProductType
, or otherwise rely on @LinkingObjects
to invert the direction of your query.
public class ProductType extends RealmObject {
@PrimaryKey
public String providerWithProductWithProductTypeId; // you must fill this yourself
@Index
public int providerId;
@Index
public int productTypeId;
@Index
public int productId;
public String productTypeName;
//public Packaging packaging;
public boolean packagingIsFree;
public long packagingValue;
@LinkingObjects("productTypes")
public final RealmResults<Product> isTypeOfProducts = null;
}
After which you could do either of
// RealmResults<Provider> resultsmRealm.where(Provider.class).equalTo("providerId", providerId).findAll();
// Product product = results.where().equalTo("providerId", providerId).findFirst().products.where().equalTo("productId", productId).findFirst();
// RealmList<ProductType> types = product.types;
RealmResults<ProductType> types = mRealm.where(ProductType.class).equalTo("providerId", providerId).findAll();
// or
RealmResults<ProductType> types = mRealm.where(ProductType.class).equalTo("isTypeOfProducts.providerId", providerId).findAll();
So if this app is not in production yet, then completely reconsider your Realm schema.
Upvotes: 1