首页 > 解决方案 > 具有空值的实体的房间(SQLite)替换策略不起作用

问题描述

我有实体类Person,表中不应该有超过一个人具有相同的namefeature。但是,如果我将人名或功能设置为 null,则它不起作用。我怎样才能使它与空值一起工作?请参阅下面的代码。

测试

Context context = InstrumentationRegistry.getContext();
AppDb db = Room.inMemoryDatabaseBuilder(context, AppDb.class).allowMainThreadQueries().build();
PersonDao dao = db.personDao();

// replacement works here
dao.insert(new Person("Musk", "Alien"));
dao.insert(new Person("Musk", "Alien"));

// replacement doesn't work here
dao.insert(new Person("Trump", null));
dao.insert(new Person("Trump", null));

// fails - actual size = 3 (Musk, Trump, Trump)
assertEquals(2, dao.getAll().size());

人.java

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Index;
import androidx.room.PrimaryKey;

@Entity(tableName = "person", indices = {@Index(value = {"name", "feature"}, unique = true)})
public class Person {

    @ColumnInfo(name = "id") @PrimaryKey(autoGenerate = true) private int id;
    @ColumnInfo(name = "name") private String name;
    @ColumnInfo(name = "feature") private String feature;

    public Person(String name, String feature) {
        this.name = name;
        this.feature = feature;
    }
    public void setId(int id) { this.id = id; }
    public int getId() { return id; }
    public String getName() { return name; }
    public String getFeature() { return feature; }
}

PersonDao.java

import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import java.util.List;

@Dao
public interface PersonDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(Person person);

    @Query("SELECT * FROM person")
    List<Person> getAll();

    @Query("SELECT * FROM person WHERE feature = :feature")
    List<Person> getByFeature(String feature);

}

AppDb.java

import androidx.room.Database;
import androidx.room.RoomDatabase;

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

    public abstract PersonDao personDao();
}

标签: androidandroid-sqliteandroid-room

解决方案


一个值与任何其他值null都是唯一的null,这就是为什么不会UNIQUE发生约束冲突而必须进行替换的原因。

您可以使您的feature字段@NonNull使 null 不是有效值,如果它为空,那么您可以使用默认/魔术值,例如"NONE".

或者,如果您不真正使用id,则可以将其删除并更改PRIMARY KEYname字段,以便Person替换具有相同名称但不同功能的插入。


推荐阅读