【问题标题】:Foreign key constraints in Android using SQLite? on Delete cascadeAndroid中使用SQLite的外键约束?在删除级联
【发布时间】:2011-02-02 11:39:14
【问题描述】:

我有两张表:tracks 和 waypoints,一个track 可以有很多waypoints,但是一个waypoint 只能分配给一个track。

在路点表中,我有一个名为“trackidfk”的列,它会在创建轨道后插入 track_ID,但是我没有在此列上设置外键约束。

当我删除一个轨迹时,我想删除分配的航点,这可能吗?我阅读了有关使用触发器的信息,但我认为 Android 不支持它们。

创建航点表:

public void onCreate(SQLiteDatabase db) {
    db.execSQL( "CREATE TABLE " + TABLE_NAME 
                + " (" 
                + _ID         + " INTEGER PRIMARY KEY AUTOINCREMENT, " 
                + LONGITUDE   + " INTEGER," 
                + LATITUDE    + " INTEGER," 
                + TIME        + " INTEGER,"
                + TRACK_ID_FK + " INTEGER"
                + " );"
              );

    ...
}

【问题讨论】:

    标签: java android sqlite foreign-keys


    【解决方案1】:

    支持带有 on delete 级联的外键约束,但您需要启用它们。
    我刚刚在我的 SQLOpenHelper 中添加了以下内容,这似乎可以解决问题。

    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        if (!db.isReadOnly()) {
            // Enable foreign key constraints
            db.execSQL("PRAGMA foreign_keys=ON;");
        }
    }
    

    我声明我的引用列如下。

    mailbox_id INTEGER REFERENCES mailboxes ON DELETE CASCADE
    

    【讨论】:

    • 这意味着它只适用于具有 SQLite 3.6.22 的 Android 2.2 Froyo
    • @RedPlanet - 这是因为只有在将某些内容写入数据库时​​才会强制执行此约束。 (如果你所做的一切都是从数据库中读取,你就不能打破这个约束)另外,Phil,而不是 onOpen 方法,在 onConfigure 方法中可能会更好。来源:developer.android.com/reference/android/database/sqlite/…
    • Google 建议在 onConfigure() 中写入 PRAGMA 语句,但它需要 API 级别 16 (Android 4.1),到那时您可以简单地调用 setForeignKeyConstraintsEnabled
    • 可能还需要考虑在onCreate/onDowngrade/onUpgrade 中启用外键约束,它们在onOpen 之前。见source code in Android 4.1.1
    • @Natix 包括对 super 的调用可确保在实现的类与其父级之间引入中间类时功能正确。
    【解决方案2】:

    自 Android 4.1 (API 16) SQLiteDatabase 支持:

    public void setForeignKeyConstraintsEnabled (boolean enable)
    

    【讨论】:

      【解决方案3】:

      正如 e.shishkin 的帖子所说,从 API 16 开始,您应该使用 db.setForeignKeyConstraintsEnabled(boolean)SqLiteOpenHelper.onConfigure(SqLiteDatabase) 方法中启用外键约束

      @Override
      public void onConfigure(SQLiteDatabase db){
          db.setForeignKeyConstraintsEnabled(true);
      }
      

      【讨论】:

        【解决方案4】:

        一个问题永远不会太老而无法用更完整的答案来回答。

        @Override public void onOpen(SQLiteDatabase db) {
            super.onOpen(db);
            if (!db.isReadOnly()) {
                setForeignKeyConstraintsEnabled(db);
            }
            mOpenHelperCallbacks.onOpen(mContext, db);
        }
        
        private void setForeignKeyConstraintsEnabled(SQLiteDatabase db) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                setForeignKeyConstraintsEnabledPreJellyBean(db);
            } else {
                setForeignKeyConstraintsEnabledPostJellyBean(db);
            }
        }
        
        private void setForeignKeyConstraintsEnabledPreJellyBean(SQLiteDatabase db) {
            db.execSQL("PRAGMA foreign_keys=ON;");
        }
        
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        private void setForeignKeyConstraintsEnabledPostJellyBean(SQLiteDatabase db) {
            db.setForeignKeyConstraintsEnabled(true);
        }
        

        【讨论】:

          【解决方案5】:

          @phil 提到的任何东西都很好。但是您可以使用另一种默认方法 数据库本身来设置外键。即 setForeignKeyConstraintsEnabled(true)。

          @Override
          public void onOpen(SQLiteDatabase db) {
              super.onOpen(db);
              if (!db.isReadOnly()) {
                  // Enable foreign key constraints
                  db.execSQL("PRAGMA foreign_keys=ON;"); 
                        //(OR)
                  db.setForeignKeyConstraintsEnabled (true)
              }
          }
          

          文档请参考SQLiteDatabase.setForeignKeyConstraintsEnabled

          【讨论】:

          • 您发布的文档建议:A good time to call this method is right after calling openOrCreateDatabase(File, SQLiteDatabase.CursorFactory) or in the onConfigure(SQLiteDatabase) callback. 因此,onConfigure 似乎是正确的地方,而不是 onOpen
          【解决方案6】:

          我认为 SQLite 不支持开箱即用。我在我的应用中所做的是:

          1. 创建事务
          2. 删除详细数据(示例中的航点)
          3. 删除主数据(示例中的轨道)
          4. 成功提交事务

          这样我可以确定要么删除所有数据,要么不删除。

          【讨论】:

          • 但是您是否使用一种方法从两个表中删除?
          • 是的,我非常喜欢 API 中的 Notes 示例。当我要删除您的情况下的轨道时,我会创建事务,删除轨道和航点并提交事务。一口气完成。
          【解决方案7】:

          android 支持触发器,sqlite 不支持这种类型的级联删除。在 android 上使用触发器的示例可以在 here 找到。尽管使用 Thorsten 所说的事务可能就像触发器一样简单。

          【讨论】:

            【解决方案8】:

            android 1.6 中的 SQLite 版本是 3.5.9,所以它不支持外键...

            http://www.sqlite.org/foreignkeys.html “本文档描述了对 SQLite 版本 3.6.19 中引入的 SQL 外键约束的支持。”

            在 Froyo 中,它是 SQLite 版本 3.6.22,所以...

            编辑: 查看 sqlite 版本: adb shell sqlite3 -version

            【讨论】:

            • 那么有没有办法强制这样的限制..我的意思是有没有办法升级sqlite版本..因为我们必须支持将软件版本支持到具有sqlite版本3.5.9的android 2.1如上
            • 不,你必须自己处理一切:(
            【解决方案9】:

            Android 2.2 及更高版本的 SQLite 支持带有“on delete cascade”的外键。但使用时要小心:有时在某一列上启动一个外键时会报错,但真正的问题在于子表中的另一列外键约束,或者其他一些引用该表的表。

            看起来 SQLite 在启动其中一个约束时会检查所有约束。它实际上在文档中提到。 DDL 与 DML 约束检查。

            【讨论】:

              【解决方案10】:

              如果您使用的是 Android Room,请执行以下操作。

              Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
                  .addCallback(object : RoomDatabase.Callback() {
                      // Called when the database has been opened.
                      override fun onOpen(db: SupportSQLiteDatabase) {
                          super.onOpen(db)
                          //True to enable foreign key constraints
                          db.setForeignKeyConstraintsEnabled(true)
                      }
              
                      // Called when the database is created for the first time. 
                      override fun onCreate(db: SupportSQLiteDatabase) {
                          super.onCreate(db)
                      }
                  }).build()
              

              【讨论】:

                猜你喜欢
                • 2011-02-24
                • 2014-01-17
                • 1970-01-01
                • 1970-01-01
                • 2019-12-24
                • 2019-04-26
                • 2020-09-01
                相关资源
                最近更新 更多