将数据库模型与网络模型分开

3

我正在使用GreenDAO和Volley。所以我有以下问题:当我进行网络请求时,我需要使用GSON解析,以便我有一个模型来表示从服务器检索到的实体和另一个模型来表示GreenDAO对象。是否有任何办法只拥有每个模型的1个类,以表示为GSON和ORM的Class?

类Product:

@SerializedName("id")
private String id;

@SerializedName("pictures")
private List<Picture> pictures;

get & set

持久化产品类:

private Long id;
private List<Picture> pictures;

/** To-many relationship, resolved on first access (and after reset). Changes to to-many relations are not persisted, make changes to the target entity. */
public List<PersistencePicture> getPictures() {
    if (pictures == null) {
        if (daoSession == null) {
            throw new DaoException("Entity is detached from DAO context");
        }
        PersistencePictureDao targetDao = daoSession.getPersistencePictureDao();
        List<PersistencePicture> picturesNew = targetDao._queryPersistenceProduct_Pictures(id);
        synchronized (this) {
            if(pictures == null) {
                pictures = picturesNew;
            }
        }
    }
    return pictures;
}

一开始我想创建一个接口,但是当你从DAO检索数据时,DAO返回的是类而不是接口,因此我认为无法以这种方式实现。我找到的唯一解决方案是创建一个“ProductUtils”,将“PersistentProduct”转换为“Product”,反之亦然。

1个回答

1
最优雅的方式是实现一个小的扩展程序,用于greendao,这样您可以在模式创建期间指定序列化名称。
例如:

de.greenrobot.daogenerator.Property.java:

// in PropertyBuilder append these lines
public PropertyBuilder setSerializedName(String sname) {
    // Check the sname on correctness (i.e. not empty, not containing illegal characters)
    property.serializedName = sname;
    return this;
}

// in Property append these lines
private String serializedName = null;

public boolean isSerialized() {
    return serializedName != null;
}

entity.ftl 文件中,在第 24 行后添加以下代码(在 package ${entity.javaPackage}; 后面):
<#if property.serializedName??>
import com.google.gson.annotations.SerializedName;
</#if>

在第55行之后(在<#list entity.properties as property>之后)

<#if property.serializedName??>
@SerializedName("${property.serializedName}")
</#if>

接下来,您应该能够使用生成的GreenDao实体与Volley配合使用,但有以下限制

  1. 如果您通过网络获取了一个产品,则数据库中不会发生任何更改。您需要调用insertOrReplace()
  2. 如果您从数据库中获取一个产品并通过网络发送它,则可能会序列化一些不需要的字段(例如myDaodaoSession)。
  3. 如果您通过网络获取一个产品并调用insertOrReplace(),则“网络”产品将被持久化,并且已经存在的产品将被替换为它,但是如果没有针对每个引用实体调用insertOrReplace(),则这些引用实体不会被更新或持久化!
  4. 如果您通过网络获取一个产品并对每个引用实体调用insertOrReplace(),则仍然引用了由DB-Product引用的所有toMany()-entities,尽管它们未在更新的Product中列出。您需要调用resetPictures()getPictures()以获取正确的列表,其中包含由存储在DB中的原始Product或通过网络更新的Product引用的所有toMany()-entities。

更新解决方案 2。

为了防止 daoSessionmyDao 被序列化,您可以使用以下 ExclusionStrategy

private static class TransientExclusionStrategy implements ExclusionStrategy {
    public boolean shouldSkipClass(Class<?> clazz) {
        return (clazz.getModifiers() & java.lang.reflect.Modifier.TRANSIENT) != 0;
    }

    public boolean shouldSkipField(FieldAttributes f) {
        return f.hasModifier(java.lang.reflect.Modifier.TRANSIENT);
    }
}

更新解决问题1、3和4。

作为快速解决方案,您可以在实体的KEEP-SECTIONS中添加以下方法:

public void merge(DaoSession s) {
    s.insertOrReplace(this);

    // do this for all toMany-relations accordingly
    for (Picture p : getPictures()) {
        s.insertOrReplace(p);
        newPics.add(p.getId());
    }
    resetPictures();
}

这将导致原始实体被更新并附加到会话和dao中。此外,由网络产品引用的每个图片都将被持久化或更新。原始实体引用但网络实体未引用的图片保持不变,并合并到列表中。
这还远非完美,但它显示了要去哪里以及要做什么。下一步是在一个事务内执行merge()中完成的所有操作,然后将不同的merge方法集成到dao.ftl中。
注意:本答案中给出的代码既不完整也未经过测试,只是提示如何解决此问题。正如上面指出的,此解决方案仍存在一些限制,必须加以处理。

嗨,感谢你的回答。那么,对于我写给你的示例中关系的问题,如何解决一个产品有多个图片的情况呢?GreenDAO生成了一个“getPictures”方法,它是一个dao访问器,从BDD获取图片。如果您解析了json响应,那么在这种情况下,您实际上不需要此方法,因为您已经解析了它。那么如何管理greenDAO的“getPictures”和可能的其他getter “getVolleyPictures”? - PaNaVTEC
@PaNaVTEC 你需要修改相应的方法以适应你的需求。这可以通过编辑 'entity.ftl' 来完成。由于我还没有使用过gson和volley,所以暂时无法给你更多提示。 - AlexS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接