Realm y Comportamiento de incremento automático (Android)

Estoy tratando de obtener datos de Realm usando un ID como referencia. Sin embargo, al consultar un ID, he encontrado que Realm me está dando el mismo ID para todos los elementos (ID de 0). ¿Por qué el ID no se incrementa automáticamente cuando utilizo la anotación @PrimaryKey en el ID del modelo?

Esta es la clase abreviada para el modelo:

 public class Child_pages extends RealmObject { @PrimaryKey private int id_cp; private int id; private String day; private int category_id; 

Y la consulta que estoy ejecutando es: realm.where(Child_pages.class).equalTo("id_cp",page_id).findFirst()

Realm actualmente no admite claves primarias de incremento automático. Sin embargo, puede implementarlo fácilmente usando algo como:

 public int getNextKey() { try { Number number = realm.where(object).max("id"); if (number != null) { return number.intValue() + 1; } else { return 0; } } catch (ArrayIndexOutOfBoundsException e) { return 0; } } 

Espero que pueda empezar.

El enlace Java no admite las claves primarias todavía, pero está en el mapa de ruta y con alta prioridad. Consulte: https://groups.google.com/forum/#!topic/realm-java/6hFqdyoH67w . Como solución, puede utilizar este código para generar claves:

 int key; try { key = realm.where(Child_pages.class).max("id").intValue() + 1; } catch(ArrayIndexOutOfBoundsException ex) { key = 0; } 

Utilizo la fábrica del singleton para generar las llaves primarias como una solución más genérica con un mejor funcionamiento (ninguna necesidad de preguntar para el max("id") cada vez gracias a AtomicInteger ).

Hay una larga discusión en Realm Git Hub si necesitas más contexto: Documente cómo configurar un auto incremento id?

Como ya se mencionó, auto-incremento aún no es compatible.

Pero para aquellos que usan kotlin y quiere tener un comportamiento de incremento automático con el reino, esta es una de las posibilidades:

 open class Route( @PrimaryKey open var id: Long? = null, open var total: Double? = null, open var durationText: String? = null, open var durationMinutes: Double? = null, open var distanceText: String? = null, open var distanceMeters: Int? = null): RealmObject() { companion object { @Ignore var cachedNextId:Long? = null get() { val nextId = if (field!=null) field?.plus(1) else Realm.getDefaultInstance()?.where(Route::class.java)?.max("id")?.toLong()?.plus(1) ?: 1 Route.cachedNextId = nextId return nextId } }} 

Si su Id es largo entonces:

 val nextId = bgRealm.where(Branch::class.java).max("localId") as Long + 1 

Lamentablemente, no puedo comentar sobre otras respuestas, pero me gustaría añadir a la respuesta de Vinicius .

En primer lugar, no debe abrir una instancia de nuevo reino, cuando se busca la clave principal, especialmente cuando no se cierra, ya que esto se agrega a máximo número posible de descriptor de archivo.

En segundo lugar, aunque esto es una preferencia, no debería tener tipos primitivos (u objetos equivalentes) como nulos (en Kotlin ), ya que esto agrega requisito redundante para comprobar la nulidad.

En tercer lugar, ya que está usando kotlin, sólo puede definir un método de extensión a la clase Realm , como por ejemplo:

 fun Realm.getNextId(model: RealmModel, idField : String) : Long { val count = realm.where(model::class.java).max(idField) return count + 1L } 

Dado que todas RealmObject instancias de RealmObject son RealmModel , e incluso los objetos que no son rastreados por Realm siguen siendo instancias de RealmModel , por lo tanto, estará disponible RealmModel que utilice sus clases relacionadas con el reino. El equivalente de Java sería:

 static long getNextId(RealmModel object, Realm realm, String idField) { long count = realm.where(object.class).max(idField); return count + 1; } 

Nota de edición tardía: Es mejor que no utilice este enfoque si se trata de datos que pueden provenir de fuentes externas, como otras bases de datos o la Web, porque esto dará lugar a colisiones entre los datos de su base de datos interna. En su lugar, debe utilizar max([id field name]) . Vea los snippets anteriores, ya los he modificado para acomodar esta edición.

// EDIT

He encontrado esta nueva solución en este problema

 @PrimaryKey private Integer _id = RealmAutoIncrement.getInstance().getNextIdFromDomain(AccountType.class); 

// Respuesta Original

Sólo quería compartir mi intento de resolver este problema, porque no quiero pasar un valor de clave principal todo el tiempo. Primero creé una clase de base de datos para manejar el almacenamiento de un RealmObject.

 public class RealmDatabase { Realm realm; public RealmDatabase() { RealmConfiguration realmConfiguration = new RealmConfiguration.Builder() .name("test").schemaVersion(1).build(); try { realm = Realm.getInstance(realmConfiguration); } catch (Exception e) { Log.e("Realm init failed", e.getMessage()); } } protected void saveObjectIntoDatabase(final RealmObject object) { realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { bgRealm.copyToRealm(object); } }, new Realm.Transaction.OnSuccess() { @Override public void onSuccess() { // onSuccess } }, new Realm.Transaction.OnError() { @Override public void onError(Throwable error) { // onError } }); } 

Después de crear la clase de base de datos i creé una interfaz para distinguir entre objetos con una clave primaria y sin ella.

 public interface AutoIncrementable { public void setPrimaryKey(int primaryKey); public int getNextPrimaryKey(Realm realm); } 

Ahora solo necesitará editar este código del método de ejecución anterior

 if(object instanceof AutoIncrementable){ AutoIncrementable autoIncrementable = (AutoIncrementable) object; autoIncrementable.setPrimaryKey(autoIncrementable.getNextPrimaryKey(bgRealm)); bgRealm.copyToRealm((RealmObject)autoIncrementable); } else { bgRealm.copyToRealm(object); } 

Con esta solución, la lógica de la base de datos seguirá estando en una clase y esta clase puede pasar a cada clase que necesite escribir en la base de datos.

 public class Person extends RealmObject implements AutoIncrementable{ @PrimaryKey public int id; public String name; @Override public void setPrimaryKey(int primaryKey) { this.id = primaryKey; } @Override public int getNextPrimaryKey(Realm realm) { return realm.where(Person.class).max("id").intValue() + 1; } } 

Para más sugerencias, siéntase libre de dejar un comentario a continuación.

  • Cómo ver mi archivo Realm en el Realm Browser?
  • Declaración de actualización en Realm
  • No puede compilar la aplicación de Android con el reino
  • ¿Los modelos Realm realmente requieren getters y setters?
  • Convertir RealmResults <E> a Lista <E> con copyFromRealm
  • El método findFirst () del dominio devuelve null
  • Realm ORM: cómo tratar con Maps?
  • ¿Tengo que cerrar el dominio en una base por hilo, o por uso / clase-base?
  • Crear un objeto autónomo del reino en android
  • Establecer valor en un objeto realm
  • ¿Cómo comprobar el reino para la existencia de los datos del androide?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.