首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Android唯一约束无效

Android唯一约束无效
EN

Stack Overflow用户
提问于 2022-10-31 18:26:42
回答 1查看 46关注 0票数 -1

我有一把像这样的刀

代码语言:javascript
运行
复制
@Dao
public interface ActivityDAO {

    @Insert
    void insert(Activity activity);

实体的定义如下

代码语言:javascript
运行
复制
@Entity(indices = {@Index(value = {"`id_from_client`"},
        unique = true)})
public class Activity {
    @PrimaryKey(autoGenerate = true)
    public int id;

    @NotNull
    @ColumnInfo(name = "id_from_client")
    public String id_from_client;

尽管在尝试使用相同的id_from_client保存对象时,已经在id_from_client上设置了索引,但是插入不会被拒绝,行也会被添加。空间为什么不强制执行唯一的索引约束?

我可以通过导出数据库并在DB浏览器上查看来验证索引的创建,其中有一个Index具有create语句index_Activity_id_id_from_clientONActivity (id, id_from_client)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-31 19:46:51

将实体与后面的库(2.4.3和2.5.0-beta01)一起使用,由于包含在`中,所以无法成功编译。其结果是:-

代码语言:javascript
运行
复制
error: `id_from_client` referenced in the index does not exists in the Entity. Available column names:id, id_from_client
public class Activity {
       ^

改为使用:-

代码语言:javascript
运行
复制
@Entity(indices = {@Index(value = {"id_from_client"}, /*<<<<<<<<<< removed enclosing `` */
    unique = true)})

成功编译,生成的java具有适当的创建索引,如下所示:-

代码语言:javascript
运行
复制
  @Override
  public void createAllTables(SupportSQLiteDatabase _db) {
    _db.execSQL("CREATE TABLE IF NOT EXISTS `Activity` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id_from_client` TEXT NOT NULL)");
    _db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_Activity_id_from_client` ON `Activity` (`id_from_client`)");
    _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
    _db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c0bc90551cfa5dbc362321d550999680')");
  }

  • 生成的java可以通过使用Android来定位。相应的类与带有@Database注释但后缀为_Impl.

的类相同。

建议的行动

  1. 删除包含索引列
  2. 的`使用最新的

库依赖项(2.4.3)。

Demo

通过上述更改,插入非唯一id_from_client的尝试将如预期的那样失败。请考虑以下旨在测试此功能的内容:

代码语言:javascript
运行
复制
public class MainActivity extends AppCompatActivity {

    TheDatabase db;
    ActivityDAO dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        db = TheDatabase.getInstance(this);
        dao = db.getActivityDAO();
        Activity a1 = new Activity();
        a1.id=0;
        a1.id_from_client = "100";

        dao.insert(a1);
        a1.id_from_client = "200";
        dao.insert(a1);
        SupportSQLiteDatabase sdb = db.getOpenHelper().getWritableDatabase();
        Cursor csr = sdb.query("SELECT * FROM sqlite_master");
        DatabaseUtils.dumpCursor(csr);

        dao.insert(a1);
        csr = sdb.query("SELECT * FROM sqlite_master");
        DatabaseUtils.dumpCursor(csr);
        csr.close();
    }
}

也就是说,当运行前两个活动行时,应该插入模式(也就是sqlite_master将被提取并转储到日志中)。但是,由于唯一的冲突,第三个插入( id_from_client仍为200 )将失败(在所有三个插入中,id为0将导致id列的生成)。

  • 注意到.allowMainThreadQueries被用于简洁和方便的

用于演示的依赖项(在build.gradle(Module ....)中)是:-

代码语言:javascript
运行
复制
dependencies {

    ....
    implementation 'androidx.room:room-runtime:2.4.3'
    ....
    annotationProcessor 'androidx.room:room-compiler:2.4.3'
}

运行上述日志的结果是:-

代码语言:javascript
运行
复制
2022-11-01 06:33:57.745 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@17eeb83
2022-11-01 06:33:57.746 I/System.out: 0 {
2022-11-01 06:33:57.746 I/System.out:    type=table
2022-11-01 06:33:57.746 I/System.out:    name=android_metadata
2022-11-01 06:33:57.746 I/System.out:    tbl_name=android_metadata
2022-11-01 06:33:57.746 I/System.out:    rootpage=3
2022-11-01 06:33:57.746 I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
2022-11-01 06:33:57.746 I/System.out: }
2022-11-01 06:33:57.746 I/System.out: 1 {
2022-11-01 06:33:57.746 I/System.out:    type=table
2022-11-01 06:33:57.746 I/System.out:    name=Activity
2022-11-01 06:33:57.746 I/System.out:    tbl_name=Activity
2022-11-01 06:33:57.746 I/System.out:    rootpage=4
2022-11-01 06:33:57.746 I/System.out:    sql=CREATE TABLE `Activity` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id_from_client` TEXT NOT NULL)
2022-11-01 06:33:57.746 I/System.out: }
2022-11-01 06:33:57.746 I/System.out: 2 {
2022-11-01 06:33:57.746 I/System.out:    type=table
2022-11-01 06:33:57.746 I/System.out:    name=sqlite_sequence
2022-11-01 06:33:57.746 I/System.out:    tbl_name=sqlite_sequence
2022-11-01 06:33:57.747 I/System.out:    rootpage=5
2022-11-01 06:33:57.747 I/System.out:    sql=CREATE TABLE sqlite_sequence(name,seq)
2022-11-01 06:33:57.747 I/System.out: }
2022-11-01 06:33:57.747 I/System.out: 3 {
2022-11-01 06:33:57.747 I/System.out:    type=index
2022-11-01 06:33:57.747 I/System.out:    name=index_Activity_id_from_client
2022-11-01 06:33:57.747 I/System.out:    tbl_name=Activity
2022-11-01 06:33:57.747 I/System.out:    rootpage=6
2022-11-01 06:33:57.747 I/System.out:    sql=CREATE UNIQUE INDEX `index_Activity_id_from_client` ON `Activity` (`id_from_client`)
2022-11-01 06:33:57.747 I/System.out: }
2022-11-01 06:33:57.747 I/System.out: 4 {
2022-11-01 06:33:57.747 I/System.out:    type=table
2022-11-01 06:33:57.747 I/System.out:    name=room_master_table
2022-11-01 06:33:57.747 I/System.out:    tbl_name=room_master_table
2022-11-01 06:33:57.747 I/System.out:    rootpage=7
2022-11-01 06:33:57.747 I/System.out:    sql=CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
2022-11-01 06:33:57.747 I/System.out: }
2022-11-01 06:33:57.747 I/System.out: <<<<<
2022-11-01 06:33:57.748 D/AndroidRuntime: Shutting down VM
2022-11-01 06:33:57.755 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: a.a.so74267661javaroomuniqueindex, PID: 28425
    java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so74267661javaroomuniqueindex/a.a.so74267661javaroomuniqueindex.MainActivity}: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: Activity.id_from_client (code 2067 SQLITE_CONSTRAINT_UNIQUE)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: Activity.id_from_client (code 2067 SQLITE_CONSTRAINT_UNIQUE)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:938)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:88)
        at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51)
        at androidx.room.EntityInsertionAdapter.insert(EntityInsertionAdapter.java:64)
        at a.a.so74267661javaroomuniqueindex.ActivityDAO_Impl.insert(ActivityDAO_Impl.java:44)
        at a.a.so74267661javaroomuniqueindex.MainActivity.onCreate(MainActivity.java:33)
        at android.app.Activity.performCreate(Activity.java:7994)
        at android.app.Activity.performCreate(Activity.java:7978)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)  
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74267661

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档