Lorsque vous travaillez sur Android, ORMLite enregistre-t-il uniquement les objets de faible niveau? J'ai une structure de données avec des objets imbriqués, tous deux nouvellement créés, et je voudrais pouvoir les enregistrer tous les deux avec un seul appel à dao.create ()
Par exemple, j'ai la classe parent suivante.
@DatabaseTable
public class Parent {
@DatabaseField(generatedId=true)
public int id;
@DatabaseField
public String name;
@DatabaseField
public Child child;
}
et la classe enfant suivante.
@DatabaseTable
public class Child {
@DatabaseField(generatedId=true)
public int id;
@DatabaseField
public String name;
}
Je veux pouvoir faire ce qui suit.
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);
Ce faisant, l'objet parent est conservé mais pas l'objet enfant et la colonne child_id
Générée automatiquement dans la table parent est définie sur 0. Est-ce un comportement normal? Existe-t-il un moyen de conserver les objets imbriqués et de propager la clé primaire?
Depuis la version 4.27, ORMlite prend en charge les paramètres foreignAutoCreate et foreignAutoRefresh sur les @DatabaseField
annotation sur un champ:
@DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
public Child child;
Cela signifie que vous affectez votre champ child
et si le champ id
sur l'enfant n'est pas défini lorsque le parent est créé, il sera créé. foreignAutoRefresh
signifie que lorsqu'un parent est récupéré, un appel SQL distinct sera effectué pour que le champ child
soit rempli.
En faisant cela, l'objet parent est conservé mais pas l'objet enfant et la colonne child_id générée automatiquement dans la table parent est définie sur 0. Est-ce un comportement normal?
Vous pouvez également avoir plus de contrôle sur le moment où ORMLite effectue les appels à l'objet enfant en créant l'enfant avant de créer le parent.
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);
Une dernière chose à noter est que sans le foreignAutoRefresh = true
lorsque vous recherchez un objet Parent, l'objet enfant que vous récupérez uniquement voit son champ id récupéré. Si l'id est un int généré automatiquement (par exemple), le champ de nom ci-dessus ne sera pas récupéré tant que vous n'aurez pas mis à jour l'objet enfant.
// 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);
Pour plus de documentation à ce sujet, consultez la page en ligne sur Foreign Object Fields .
Avez-vous essayé cela?
@DatabaseField(foreign = true, foreignAutoCreate = true, foreignAutoRefresh = true)
public Child child;
J'utilise ORMLite 4.35.
@DatabaseField(foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true)
public Child child;
(foreignAutoCreate = true) ne fonctionne que si le champ ID n'est pas défini (null ou 0) selon la documentation ORMlite http://ormlite.com/javadoc/ormlite-core/com/j256/ormlite/field/DatabaseField .html
Cela ne fonctionne que si generateId est également défini sur true pour la table enfant selon documentation ORMlite .
Comme mentionné, cela ne semble pas être pris en charge dans la version Lite. J'ai écrit une fonction récursive simple pour enregistrer tous les objets référencés. J'ai eu du mal à faire jouer les génériques à Nice donc au final je les ai tous supprimés. J'ai également créé une classe d'entité de base pour mes objets db.
Voici donc ce que j'ai écrit. Si quelqu'un peut faire fonctionner le même code avec des génériques appropriés, ou peut l'améliorer, n'hésitez pas à le modifier.
// 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);
}