【问题标题】:Realm Query not giving correct results领域查询没有给出正确的结果
【发布时间】:2019-02-06 17:50:07
【问题描述】:

我有以下数据结构,包含在供应商列表中,有产品,每个产品都有不同的类型

提供者类

public class Provider extends RealmObject {

    @SerializedName("id")
    @PrimaryKey
    public int providerId;
    public String name;
    public RealmList<Product> products;

}

产品类别

public class Product extends RealmObject {

    @SerializedName("id")
    @PrimaryKey
    public int productId;
    public String name;
    public RealmList<ProductType> types;

}

产品类型类

public class ProductType extends RealmObject {

    @SerializedName("id")
    @PrimaryKey
    public int productTypeId;
    public String name;
    public Packaging packaging; }

这是加载到领域的 JSON 示例:

{
  "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
            }
          }
        ]
      }]
    }

    ]
}

所以,当我尝试使用以下查询获取香蕉类型时出现了我遇到的问题

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;

返回的类型列表总是给我第二个提供者的类型。在当前示例中,即使我请求提供者 ID 1(即 PROVIDER_1),我也会得到“厄瓜多尔普雷姆”,并且该提供者必须以“哥斯达黎加”和“巴西”类型返回。

【问题讨论】:

    标签: android realm


    【解决方案1】:

    你有两个或三个问题之一:

    1.) 您的 API 返回 idBananaid,但您同时获得了 Provider1 和 Provider2 的 id=10;Banana,因此保存了具有 Provider1Banana,之后,具有相同 ID 的 Provider2Banana 被保存(因此,例如,用 Provider1 覆盖原始的 Banana 而不是“合并它们”)。

    因此,您应该引入手动计算的复合键,而不是直接将 API 响应映射到 RealmObjects,这很可能是一个包含 ProviderID 和 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;
    
    }
    

    我希望这不是一个同步领域!

    2.) 您将 JSON 对象直接映射到 Realm,可能是出于“方便”,但这使您无法为查询设置最佳架构。

    实际上,“提供者”似乎并不特别重要,只是特定香蕉属于某个提供者;这可以建模为一个字段,而不是一个对象链接。

    // 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;
    
    }
    

    最重要的是,packaging 只是可以轻松合并到ProductType 中的两个字段。而且,如果Ecuador Prem 类型可以属于多个产品和多个提供者,那么它还应该有一个由所有 3 个 ID 构成的复合键!

    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.) 一旦你有了那个,你可以很容易地依靠直接检查providerId也保存到ProductType,或者依靠其他方式在@LinkingObjects 上反转查询的方向。

    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;
    }
    

    之后你可以做任何一个

    // 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();
    

    因此,如果此应用尚未投入生产,那么完全重新考虑您的 Realm 架构

    【讨论】:

    • 这是很棒的回应!还有一个问题,我必须使用 Realm 1.2.0 bcs 我在加载 32 位的其他 jni 库时遇到问题,所以我无法更新,意味着我没有可用的 LinkingObjects,这是个问题吗?
    • 只有当您没有将providerId 保存在ProductType 中时才会出现问题。在LinkingObjects之前,手动创建双向RealmList&lt;性能还可以,后来就成了瓶颈。
    猜你喜欢
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 2020-04-19
    相关资源
    最近更新 更多