Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Android上使用ORMLite保存嵌套的外来对象_Android_Ormlite - Fatal编程技术网

在Android上使用ORMLite保存嵌套的外来对象

在Android上使用ORMLite保存嵌套的外来对象,android,ormlite,Android,Ormlite,在Android上工作时,ORMLite是否只保存浅层对象?我有一个带有嵌套对象的数据结构,这两个对象都是新创建的,我希望能够通过一次对dao.create()的调用来保存这两个对象 对于exmaple,我有以下父类 @DatabaseTable public class Parent { @DatabaseField(generatedId=true) public int id; @DatabaseField public String name; @Databas

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

对于exmaple,我有以下父类

@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\u id
列将设置为0。这是正常的行为吗?有没有办法保存嵌套对象并向上传播主键?

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

@DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
public Child child;
这意味着您要分配您的
子项
字段,如果在创建父项时未设置子项上的
id
字段,则将创建该字段。
foreignAutoRefresh
意味着在检索父项时,将进行单独的SQL调用以填充
子项
字段

执行此操作时,将保留父对象,但不保留子对象,并且父表中自动生成的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
,则返回的子对象只能检索其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);

有关此功能的更多文档,请参阅联机页面。

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

这就是我写的。如果有人可以使用相同的代码来处理适当的泛型,或者可以对其进行改进,请随意编辑

    // 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);
    }
//调试标识标记
公共静态最终字符串标记=DatabaseHelper.class.getName();
//常见DAO对象的静态映射
@抑制警告(“原始类型”)
私人静态最终地图你试过这个吗

@DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
public Child child;
我用的是ORMLite 4.35

@DatabaseField(foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true)
public Child child;
关于此解决方案的一些注释
  • (foreignAutoCreate=true)仅在未根据ORMlite文档设置ID字段(null或0)时工作

    • foreignAutoCreate: “将此设置为true(默认为false),以便在未设置ID字段(null或0)时,使用其内部DAO自动创建外部字段。”
  • 仅当根据将子表的generatedId也设置为true时,此选项才有效


  • 谢谢你的反馈。我也这么想。我的问题只给出了一个简单的例子,但我真正想做的是能够存储相当复杂的对象,而不必对对象本身了解太多。我写了一个快速解决方案,我将发布,但我认为它可以改进。请将它发布到ORMLite邮件列表的@Chase。当然我注意到较新版本的ORMLite现在支持类似的功能。我已经做了很多其他的增强,我也将发布邮件列表。@gray根据ORMLite文档,你也应该做
    parent.child=child和<代码>子项=父项
    。此外,我在ChilderDao之后创建ParentDao时使用了什么,所以
    childrenDao.create(childrenDao);parentDao.create(parent)它导致子项被创建两次。可能是因为集合中的eager=true?如果'generatedId=false',是否有这样一个简单的解决方案?谢谢这个家伙。是的,我一直在考虑添加自动创建/更新外部字段的功能。但是,它不会是默认值,它将出现在另一个数据库事务中,而不是hibernate使用的魔法连接。实际上,在仔细考虑之后,通常情况下,子对象将父对象作为外部对象。帐户存在于具有外部帐户字段的订单对象之前。通常,对象的自动刷新是可能的,但是自动创建会很奇怪。我的理解是,唯一自动生成的列是用于外部对象的列,这意味着子对象不会自动创建对其父对象的引用。考虑到这一点,上面的代码对我来说运行良好,尽管我已经稍微改进了泛型。最后,我使用GSON将JSON映射到一个对象,并使用同一个对象使用ormlite在本地持久化。我不得不编写一些自定义DAO对象来加载和创建列表实体(一对多关系)。它工作得很好,但有点慢。这将是一个很好的内置功能:)我之前的评论说,ORMLite for Android不支持这些功能+因为在我看来这是正确的答案。这几乎对我有用。我的问题是,我从服务器获取ID为的外部对象,它只自动创建ID为0或null的外部对象:(如何避免手动创建外部对象?请注意,这种方法可能会影响性能。例如,在UI中,您可能会在对象标题中显示少量信息,并仅根据用户需求查询详细信息。不适用于@ForeignCollectionField,不幸的是,它工作良好,并且在我尝试创建父对象时,我的子对象也会创建。)但当我更改子对象中某个字段的值,然后调用update parent对象时,它不会自动更新子对象。你对此有什么线索吗?另请参见。虽然Gray总是参考他的页面,但对stackoverflow和