在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.这是正常行为吗?有没有办法让嵌套对象保持不变并传播主键?
答案 0 :(得分:47)
你试过这个吗?
@DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
public Child child;
我正在使用ORMLite 4.35。
答案 1 :(得分:42)
从版本4.27开始,ORMlite支持字段上@DatabaseField
注释的foreignAutoCreate和foreignAutoRefresh设置:
@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);
还有一点需要注意的是,在查询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);
有关此问题的更多文档,请参阅有关Foreign Object Fields。
的在线页面答案 2 :(得分:4)
如上所述,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);
}
答案 3 :(得分:4)
@DatabaseField(foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true)
public Child child;
(foreignAutoCreate = true)仅在未根据ORMlite文档http://ormlite.com/javadoc/ormlite-core/com/j256/ormlite/field/DatabaseField.html
设置ID字段(null或0)时起作用只有根据ORMlite documentation对子表的generatedId也设置为true时,此方法才有效。