Android中使用SQLite的外键约束?在删除级联
Posted
技术标签:
【中文标题】Android中使用SQLite的外键约束?在删除级联【英文标题】:Foreign key constraints in Android using SQLite? on Delete cascade 【发布时间】: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"
+ " );"
);
...
【问题讨论】:
【参考方案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 不支持开箱即用。我在我的应用中所做的是:
-
创建事务
删除详细数据(示例中的航点)
删除主数据(示例中的轨道)
成功提交事务
这样我可以确定要么删除所有数据,要么不删除。
【讨论】:
但是您是否使用一种方法从两个表中删除? 是的,我非常喜欢 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()
【讨论】:
以上是关于Android中使用SQLite的外键约束?在删除级联的主要内容,如果未能解决你的问题,请参考以下文章