Realm and auto increment Behavior (Android)

后端 未结 8 2084
野的像风
野的像风 2020-12-14 16:22

I\'m trying to get data from Realm using an ID as a reference. However, when querying for an ID, I\'ve found that Realm is giving me the same ID for all elements (ID of 0).

相关标签:
8条回答
  • 2020-12-14 16:54

    Sadly, I can't comment on other answers, but I'd like to add to Vinicius` answer.

    First, you shouldn't open a new realm instance, when looking for primary key, especially when you don't close them, as this adds to maximum possible file descriptor count.

    Secondly, although this is a preference, you shouldn't have primitive types (or object equivalents) as nullables (in Kotlin), as this adds redundant requirement to check nullability.

    Third, since you're using kotlin, you can just define an extension method to Realm class, such as:

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

    Since all RealmObject instances are RealmModel, and even objects that aren't tracked by Realm are still RealmModel instances, therefore it will be available where ever you use your realm related classes. Java equivalent would be:

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

    Late edit note: You're better off not using this approach if you're dealing with data that might come from outside sources, such as other databases or the web, because that WILL result in collisions between data in your internal database. Instead you should use max([id field name]). See the previous snippets, I already modified them to accommodate for this edit.

    0 讨论(0)
  • 2020-12-14 16:58

    // EDIT

    I found this new solution on this problem

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

    // Original Answer

    I just wanted to share my attempt on solving this Problem, because i don't want to pass a primary Key value all the time. First i created a Database-Class to handle the storage of a 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
            }
        });
    }
    

    After creating the database-class i created an Interface to distinguish between Objects with a Primary Key and without.

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

    Now you will just need to edit this code of the previous execute method

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

    With this solution the database logic will still be in one class and this class can passed down to every class which needs to write into the database.

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

    For further suggestions feel free to leave a comment below.

    0 讨论(0)
提交回复
热议问题