40

在Android上工作时,ORMLite是否只保存浅层对象?我有一个包含嵌套对象的数据结构,这两个都是新创建的,我希望能够通过一次调用 dao.create() 来保存它们

例如,我有以下父类。

@DatabaseTable
public class Parent {

  @DatabaseField(generatedId=true)
  public int id;

  @DatabaseField
  public String name;

  @DatabaseField
  public Child child;
}

和以下子类。

@DatabaseTable
public class Child {

  @DatabaseField(generatedId=true)
  public int id;

  @DatabaseField
  public String name;
}

我希望能够做到以下几点。

Parent parent = new Parent();
parent.name = "ParentName";

Child child = new Child();
child.name = "ChildName";

parent.child = child;

//  .. get helper and create dao object...
dao.create(parent);

这样做时,父对象被持久化,而不是子对象,并且父表中的自动生成child_id列设置为 0。这是正常行为吗?有没有办法让嵌套对象持久化并向上传播主键?

4

4 回答 4

47

你试过这个吗?

@DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
public Child child;

我正在使用 ORMLite 4.35。

于 2012-03-16T20:32:02.110 回答
43

从 4.27 版开始,ORMlite 支持字段注释的foreignAutoCreateforeignAutoRefresh设置@DatabaseField

@DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
public Child child;

这意味着您分配了您的child字段,如果在id创建父项时未设置子项上的字段,则将创建它。这foreignAutoRefresh意味着当检索父级时,将进行单独的 SQL 调用以child填充该字段。

这样做时,父对象被持久化,而不是子对象,并且父表中自动生成的 child_id 列设置为 0。这是正常行为吗?

您还可以通过在创建父对象之前创建子对象来更好地控制 ORMLite 何时调用子对象。

Parent parent = new Parent();
parent.name = "ParentName";

Child child = new Child();
child.name = "ChildName";

parent.child = child;

// this will update the id in child
childDao.create(child);

// this saves the parent with the id of the child
parentDao.create(parent);

还有一点需要注意的是,如果没有foreignAutoRefresh = true查询 Parent 对象,则返回的子对象只会检索其 id 字段。如果 id 是自动生成的 int(例如),则在您对子对象进行更新之前,不会检索上述名称字段。

// assuming the id of the Parent is the name
Parent parent = parentDao.queryForId("ParentName");
System.out.println("Child id should be set: " + parent.child.id);
System.out.println("Child name should be null: " + parent.child.name);

// now we refresh the child object to load all of the fields
childDao.refresh(parent.child);
System.out.println("Child name should now be set: " + parent.child.name);

有关这方面的更多文档,请参阅有关Foreign Object Fields的在线页面。

于 2011-01-20T14:39:30.967 回答
4

如前所述,精简版似乎不支持此功能。我写了一个简单的递归函数来保存所有引用的对象。我在让泛型发挥得很好时遇到了问题,所以最后我把它们全部删除了。我还为我的数据库对象创建了一个基本实体类。

所以这就是我写的。如果任何人都可以获得相同的代码来使用适当的泛型,或者可以对其进行改进,请随时编辑。

    // Debugging identity tag
    public static final String TAG = DatabaseHelper.class.getName();

    // Static map of common DAO objects
    @SuppressWarnings("rawtypes")
    private static final Map<Class, Dao<?, Integer>> sDaoClassMap = new HashMap<Class, Dao<?,Integer>>();

    /**
     * Persist an entity to the underlying database.
     * 
     * @param context
     * @param entity
     * @return boolean flag indicating success
     */
    public static boolean create(Context context, Entity entity) {
        // Get our database manager
        DatabaseHelper databaseHelper = DatabaseHelper.getHelper(context);

        try {
            // Recursively save entity
            create(databaseHelper, entity);

        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Object is not an instance of the declaring class", e);
            return false;
        } catch (IllegalAccessException e) {
            Log.e(TAG, "Field is not accessible from the current context", e);
            return false;
        } catch (SQLException e) {
            Log.e(TAG, "Unable to create object", e);
            return false;
        }

        // Release database helper
        DatabaseHelper.release();

        // Return true on success
        return true;
    }

    /**
     * Persist an entity to the underlying database.<br><br>
     * For each field that has a DatabaseField annotation with foreign set to true, 
     * and is an instance of Entity, recursive attempt to persist that entity as well. 
     * 
     * @param databaseHelper
     * @param entity
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws SQLException
     */
    @SuppressWarnings("unchecked")
    public static void create(DatabaseHelper databaseHelper, Entity entity) throws IllegalArgumentException, IllegalAccessException, SQLException {
        // Class type of entity used for reflection
        @SuppressWarnings("rawtypes")
        Class clazz = entity.getClass();

        // Search declared fields and save child entities before saving parent. 
        for(Field field : clazz.getDeclaredFields()) {
            // Inspect annotations
            for(Annotation annotation : field.getDeclaredAnnotations()) {
                // Only consider fields with the DatabaseField annotation
                if(annotation instanceof DatabaseField) {
                    // Check for foreign attribute
                    DatabaseField databaseField = (DatabaseField)annotation;
                    if(databaseField.foreign()) {
                        // Check for instance of Entity
                        Object object = field.get(entity);                      
                        if(object instanceof Entity) {
                            // Recursive persist referenced entity
                            create(databaseHelper, (Entity)object);
                        }
                    }
                }
            }
        }

        // Retrieve the common DAO for the entity class
        Dao<Entity, Integer> dao = (Dao<Entity, Integer>) sDaoClassMap.get(clazz);
        // If the DAO does not exist, create it and add it to the static map
        if(dao == null) {
            dao = BaseDaoImpl.createDao(databaseHelper.getConnectionSource(), clazz);
            sDaoClassMap.put(clazz, dao);
        }

        // Persist the entity to the database
        dao.create(entity);
    }
于 2011-01-21T03:26:07.057 回答
4
@DatabaseField(foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true)
public Child child;

关于此解决方案的一些注意事项

  1. (foreignAutoCreate = true) 仅在根据 ORMlite 文档http://ormlite.com/javadoc/ormlite-core/com/j256/ormlite/field/DatabaseField.html未设置 ID 字段(null 或 0)时工作

    • foreignAutoCreate :“将此设置为 true(默认为 false),如果 ID 字段未设置(null 或 0),则将使用其内部 DAO 自动创建外部字段。”
  2. 这仅适用于根据ORMlite 文档将子表的 generatedId 也设置为 true 的情况。

于 2013-10-12T22:00:38.957 回答