40 votes

Enregistrement d'objets étrangers imbriqués avec ORMLite sur Android

Lorsque vous travaillez sur Android, ne ORMLite seulement d'économiser de faible niveau des objets? J'ai une structure de données avec des Objets imbriqués, qui sont tous deux nouvellement créé, et je voudrais être en mesure de sauver tous les deux avec un appel à la dao.créer()

Pour exemple, j'ai le texte suivant Classe Parent.

@DatabaseTable
public class Parent {

  @DatabaseField(generatedId=true)
  public int id;

  @DatabaseField
  public String name;

  @DatabaseField
  public Child child;
}

et suivants de la Classe Enfant.

@DatabaseTable
public class Child {

  @DatabaseField(generatedId=true)
  public int id;

  @DatabaseField
  public String name;
}

Je veux être en mesure de 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);

En faisant cela, le parent de l'objet est conservé, mais pas l'enfant de l'objet et de l'auto-générés child_id colonne dans la table parent est mis à 0. Est-ce un comportement normal? Est-il possible d'avoir des objets imbriqués ont persisté et se propager à la clé primaire jusqu'?

47voto

lstrzelecki Points 257

Avez-vous essayé cela?

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

J'utilise ormlite 4.35.

43voto

Gray Points 58585

En faisant cela, le parent de l'objet est conservé, mais pas l'enfant de l'objet et de l'auto-générés child_id colonne dans la table parent est mis à 0. Est-ce un comportement normal?

OrmLite n'est pas auto-enregistrer les objets imbriqués automatiquement comme les autres Orm. Il est conçu en prenant de la "petite" partie de son nom au sérieux et avec le BAISER devise à l'esprit.

Cependant, vous pouvez facilement obtenir des objets imbriqués de travail par la création de 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 chose à noter est que lorsque vous effectuez une requête pour un objet Parent, l'enfant de l'objet que vous obtenez de retour seulement a son champ id récupéré. Si l'id est généré automatiquement et int (par exemple), puis au-dessus du nom de domaine ne seront pas récupérés jusqu'à ce que vous faire une mise à jour sur 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, voir la page en ligne à propos de l'Étranger Objet de Champs.

4voto

Chase Points 7520

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 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);
    }
 

4voto

Ayman Mahgoub Points 505
@DatabaseField(foreign = true,foreignAutoCreate = true,foreignAutoRefresh = true)
public Child child;

Quelques Notes sur cette solution

1- (foreignAutoCreate = true) fonctionne uniquement si le champ ID n'est pas définie (null ou 0) selon ORMlite documentation http://ormlite.com/javadoc/ormlite-core/com/j256/ormlite/field/DatabaseField.html

  • foreignAutoCreate : "Cette définie sur true (false par défaut) pour avoir le champ étranger seront automatiquement créés à l'aide de son système interne de DAO si le champ ID n'est pas définie (null ou 0)."

2 - Cela ne fonctionne que si generatedId est également définie sur true pour l'enfant tableau selon ORMlite documentation http://ormlite.com/javadoc/ormlite-core/doc-files/ormlite_2.html#foreignAutoCreate

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X