Unable to Update using @PrimaryKey(autoGenerate = true)

Issue

I am working with Room and have found an issue with setting primary key to autogenerate,

@PrimaryKey(autoGenerate = true)

If I do an INSERT operation and then follow that up with an UPDATE operation, the generated keys for these operations differ and therefore, my data does not get updated.

@Entity(tableName = "test_table")
public class TestEntity {

    @PrimaryKey(autoGenerate = true)
    private int uid;

    @ColumnInfo(name = "expiration_date_access_token")
    private String expirationDateAccessToken;


    /**
     * Getter for retrieving primary key
     *
     * @return Primary key
     */
    public int getUid() {
        return uid;
    }

    /**
     * Setter for setting primary key
     *
     * @param uid Primary key
     */
    public void setUid(int uid) {
        this.uid = uid;
    }

    /**
     * Getter for retrieving expiration date of access token
     *
     * @return Expiration date of access token
     */
    public String getExpirationDateAccessToken() {
        return expirationDateAccessToken;
    }

    /**
     * Setter for setting expiration date of access token
     *
     * @param expirationDateAccessToken Expiration date of access token
     */
    public void setExpirationDateAccessToken(String expirationDateAccessToken) {
        this.expirationDateAccessToken = expirationDateAccessToken;
    }
}

Here is an example DAO

@Dao
public interface TestDao {

    @Query("SELECT * FROM test_table")
    List<TestEntity> getAll();

    @Query("DELETE FROM test_table")
    void deleteAll();

    @Insert
    void insert(TestEntity testEntity);

    @Delete
    void delete(TestEntity testEntity);

    @Update
    void update(TestEntity testEntity);
}

Here is my AppDatabase

@Database(entities = {TestEntity.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {

    private static final String DATABASE_NAME = "room.test.db";
    private static AppDatabase APP_DATABASE_INSTANCE;

    public abstract TestDao testDao();

    public static AppDatabase getAppdatabase(@NonNull Context context) {
        if (FrameworkUtils.checkIfNull(APP_DATABASE_INSTANCE)) {
            APP_DATABASE_INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                    AppDatabase.class, DATABASE_NAME).build();
        }
        return APP_DATABASE_INSTANCE;
    }

    /**
     * Method is used to destroy database instance
     */
    public static void destroy() {
        APP_DATABASE_INSTANCE = null;
    }
}

I have connected my LiveData to my repository, howevever, for simplistic reasons below also does the same operation.

Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                // update database tables
               TestEntity testEntity = new TestEntity();
               // if I uncomment setting uid, which is the hardcoded primary key
               // value, the update will happen. If I do not include this, and 
               // just try to update my data, a new primary key is generated and
               // the old data does not get updated.

               // testEntity.setUid(1); 
               testEntity.setExpirationDateAccessToken("12345");
               AppDatabase.getAppdatabase(context).testDao().update(testEntity);

            }
        });

My question is, what is the pattern for using @PrimaryKey(autoGenerate = true)?? I can get everything to work perfectly by doing the following hardcoding of the primary key, but I did not think that was required.

EDIT

    @PrimaryKey(autoGenerate = true)
    private int uid = 1; <---- works with any hardcoded int value

Solution

You create a TestEntity and then tell Room to save it in the database. At that point, Room assign to it a autogenerated primary key. If then you want to update that specific TestEntity, you have to pass an instance of TestEntity class with the exact same id that the database is using (the id is automatically generated when the entity is saved for the first time in the database, not when you instantiate it).

Therefore, you have to know the id of the entity you want to update. How to tell which id is assigned to it when it is first saved? You can make your @Insert method return a Long instead, which will be the id.

@Insert
Long insert(TestEntity testEntity);

So, with that little change, you can now know which id the databse assigned to the recently saved Entity. Then, you can set that Long to the Entity instance in java, change some other parameter, and call update, and it will work because they will have the same id this time

Answered By – dglozano

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published