无法使用@PrimaryKey(autoGenerate = true)更新

时间:2018-11-30 17:41:28

标签: android sqlite android-room

我正在与Room一起工作,但发现将主键设置为自动生成时出现了问题,

  

@PrimaryKey(autoGenerate = true)

如果我先执行INSERT操作,然后再执行UPDATE操作,则这些操作生成的密钥会有所不同,因此我的数据不会得到更新。

NullPointerException

这是DAO的示例

Room newRoom = new Room();
newRoom.setName(meetingRoom[0]);
newRoom.setCode(meetingRoom[1]);
few more setters ...
home.addRoom(newRoom);

这是我的AppDatabase

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

但是,由于以下简单的原因,我已将LiveData连接到我的存储库。

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

我的问题是,使用@PrimaryKey(autoGenerate = true)的模式是什么?通过对主键进行以​​下硬编码,我可以使一切正常工作,但是我认为这不是必需的。

编辑

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

2 个答案:

答案 0 :(得分:2)

您创建一个TestEntity,然后告诉Room将其保存在数据库中。此时,Room为其分配了一个自动生成的主键。如果要更新特定的TestEntity,则必须传递TestEntity类的实例,该实例的ID与数据库使用的ID完全相同(在为该实体保存实体时会自动生成该ID)第一次在数据库中,而不是在实例化时。)

因此,您必须知道要更新的实体的ID。首次保存时,如何知道分配给哪个ID?您可以使您的@Insert方法返回一个Long,它是id。

@Insert
Long insert(TestEntity testEntity);

因此,只需进行很小的更改,您现在就可以知道数据库分配给最近保存的实体的ID。然后,您可以在Java中将Long设置为Entity实例,更改其他参数,然后调用update,因为它这次具有相同的ID,所以它将起作用

答案 1 :(得分:1)

  

我的问题是,使用@PrimaryKey(autoGenerate = true)的模式是什么?

  • 它的简单整数从0开始,然后随着行的增加而递增1。
  

我是否必须始终检索ID,然后在每次更新时都将其传入?

  • 是的。 @Update-来自文档

该方法的实现将更新其在数据库中的参数(如果它们已经存在)(通过主键检查)。如果它们尚不存在,则此选项将不会更改数据库。

  

必须有更好的方法。有什么建议吗?

  • 这取决于您的要求。 如果我没记错的话,我想你总是试图只在表中保存一行。
  

@Query(“ UPDATE test_table where 1 = 1”)

     

受保护的抽象int update(TestEntity te);

替代方式。但是在这里,您需要设置uid一些硬编码的整数。 由于您不存储多个,所以不需要主键约束,上述任何逻辑都将起作用。