Java Android中使用SQLite的外键约束?关于删除级联

Java Android中使用SQLite的外键约束?关于删除级联,java,android,sqlite,foreign-keys,Java,Android,Sqlite,Foreign Keys,我有两个表格:轨道和航路点,一条轨道可以有许多航路点,但一个航路点只分配给一条轨道 在way points表中,我有一个名为“trackidfk”的列,它在创建轨迹后插入轨迹ID,但是我没有在此列上设置外键约束 当我删除轨道时,我想删除指定的航路点,这可能吗?。我读过关于使用触发器的文章,但我认为Android不支持触发器 要创建航路点表,请执行以下操作: public void onCreate(SQLiteDatabase db) { db.execSQL( "CREATE TABL

我有两个表格:轨道和航路点,一条轨道可以有许多航路点,但一个航路点只分配给一条轨道

在way points表中,我有一个名为“trackidfk”的列,它在创建轨迹后插入轨迹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"
                + " );"
              );

    ...
}

我认为SQLite不支持这种开箱即用的方式。我在应用程序中所做的是:

  • 创建事务
  • 删除详细数据(示例中的航路点)
  • 删除主数据(示例中的轨迹)
  • 成功提交事务

  • 通过这种方式,我确定要么删除所有数据,要么不删除任何数据。

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

    支持带on delete cascade的外键约束,但您需要启用它们。
    我刚刚将以下内容添加到我的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
    

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

    “本文档描述了对SQLite版本3.6.19中引入的SQL外键约束的支持。”

    在Froyo中是SQLite版本3.6.22,所以

    编辑: 要查看sqlite版本:Android 2.2及更高版本的sqlite支持adb shell sqlite3版本

    外键和“on delete cascade”。但在使用它们时要小心:有时在一列上启动一个外键时会报告错误,但真正的问题在于子表中的另一列外键约束,或者某个其他表引用此表

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

    因为Android 4.1(API 16)支持:

    public void setForeignKeyConstraintsEnabled (boolean enable)
    

    正如e.shishkin在API 16上的帖子所说,您应该使用
    db.setForeignKeyConstraintEnabled(布尔值)
    SqLiteOpenHelper.onConfigure(SqLiteDatabase)
    方法中启用外键约束


    无论@phil提到什么都是好的。但您可以使用中提供的另一个默认方法 数据库本身来设置foreignkey。这是setForeignKeyConstraintEnabled(true)


    有关文档,请参阅“永远不要太老的问题”以获得更完整的答案

    @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);
    }
    
    @覆盖公共void onOpen(SQLiteDatabase db){
    super.onOpen(db);
    如果(!db.isReadOnly()){
    SetForeignKeyConstraintEnabled(db);
    }
    onOpen(mContext,db);
    }
    私有void setForeignKeyConstraintEnabled(SQLiteDatabase db){
    if(Build.VERSION.SDK\u INT
    如果您使用的是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()
    

    但是您是否使用一种方法从两个表中删除?是的,我非常赞同API中的Notes示例。在您的情况下,当我要删除轨道时,我会创建事务、删除轨道和航路点并提交事务。这一切都是一次性的,这意味着它只有在安卓2.2Froyo之后才能工作,而安卓2.2Froyo有SQLITE3.6。22@RedPlanet-这是因为只有在将某些内容写入数据库时才强制执行此约束。(如果您所做的一切都是从数据库中读取,则无法打破此约束)另外,Phil,与其使用onOpen方法,不如使用onConfigure方法。源代码:谷歌建议编写“代码> PrasMa<代码>语句,但它需要API级别16(Android 4.1),然后可以简单地调用。一个还需要考虑在代码< OnCudio< /代码> /<代码> OnDevel < <代码> >代码>升级> <代码>之前启用外键约束。请参阅。@Natix包括对super的调用,以确保在实现的类和其父类之间引入中间类时功能正确。那么是否有任何方法强制执行此类约束。。我的意思是有没有办法升级sqlite版本。。因为我们必须支持android 2.1的软件版本,该版本的sqlite版本为3.5.9,如上所述。不,您必须自己处理所有事情:(您发布的文档建议:
    调用此方法的好时机是在调用openOrCreateDatabase(File,SQLiteDatabase.CursorFactory)之后或在onConfigure中(SQLiteDatabase)回调。
    因此,与打开相比,
    onconfig
    似乎是正确的位置。
    @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);
    }
    
    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()