问题描述
package com.example.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.sqliteDatabase;
import android.database.sqlite.sqliteOpenHelper;
public class DatabaseHelper extends sqliteOpenHelper {
//making db and setting tables 1-6 names
private static final int DATABASE_VERSION = 4;
private static final String DATABASE_NAME = "contacts.db";
private static final String TABLE1_NAME = "contacts";
private static final String TABLE2_NAME = "Uinfo";
private static final String TABLE3_NAME = "exercises";
private static final String TABLE4_NAME = "calories";
private static final String TABLE5_NAME = "calendar";
// private static final String TABLE6_NAME = "settings";
//these are for table 1
private static final String COLUMN_ID = "id";
private static final String COLUMN_EMAIL = "email";
private static final String COLUMN_PASS = "pass";
private static final String COLUMN_UNAME = "uname";
private static final String COLUMN_NAME = "name";
//for table 2
private static final String COLUMN_ID2 = "id2";
private static final String COLUMN_AGE = "age";
private static final String COLUMN_WEIGHT = "weight";
private static final String COLUMN_HEIGHT = "height";
private static final String COLUMN_SEX = "sex";
private static final String COLUMN_FK_CONTACTS_ID = "id";
// private static final String COLUMN_FK_SETTINGS_ID = "id_6";
private static final String COLUMN_FK_CALENDAR_ID = "id5";
//creating tables
private static final String TABLE_CREATE = "create table " + TABLE1_NAME +
" (id integer primary key AUTOINCREMENT not null," +
" name text not null," +
" email text not null," +
" pass text not null," +
" uname text not null);";
private static final String TABLE2_CREATE = "create table " + TABLE2_NAME +
"(id2 integer primary key AUTOINCREMENT not null," +
" age text not null," +
" weight text not null," +
" height text not null," +
" sex text not null," +
" FOREIGN KEY ("+ COLUMN_ID2 +") REFERENCES "+TABLE1_NAME+"("+COLUMN_ID+")," +
" FOREIGN KEY ("+ COLUMN_ID2 +") REFERENCES "+TABLE5_NAME+"("+COLUMN_ID5+"));";
//" FOREIGN KEY ("+ COLUMN_ID2 +") REFERENCES "+TABLE6_NAME+"("+COLUMN_ID6+"));";
基本上外键在查看时不会出现在数据库中。 我试过加入
"id integer not null"
在第一个外键行之前,这使数据库停止向该表写入数据。我已经更新了数据库版本,看看这是否也会有所作为,但无济于事。 我叫错了吗?我可能只是错过了在外键进入的列中写入的正确方法。虽然我不确定它会如何以正确的方式插入。
解决方法
我认为您的问题是对 FOREIGN KEY .... 子句的作用的误解。
它不会创建用于存储外键的列。相反,它添加了一个约束(规则),表明正在创建的表中的列必须包含在 REFERENCES 之后指定的表(列)中的现有值。
这些陈述是正确的,实际上确实创建了外键约束;如将显示的那样。
考虑以下内容(通过使用您提供的 Android Studio 运行代码(加上代码以使其可用),从而创建数据库和所需的表)
- 在创建 Uinfo 表(以及其他表)并从 TABLE2_CREATE 变量复制值时使用 DEBUG 停止,获得的值是:-
create table Uinfo(id2 integer primary key AUTOINCREMENT not null,age text not null,weight text not null,height text not null,sex text not null,FOREIGN KEY (id2) REFERENCES contacts(id),FOREIGN KEY (id2) REFERENCES calendar(id5));
将此值放入 SQLite 工具 (navicat) 中,然后运行以下 SQL:-
create table contacts (id integer primary key AUTOINCREMENT not null,name text not null,email text not null,pass text not null,uname text not null);
CREATE TABLE calendar(id5 INTEGER PRIMARY KEY,other TEXT);
create table Uinfo(id2 integer primary key AUTOINCREMENT not null,FOREIGN KEY (id2) REFERENCES calendar(id5));
SELECT * FROM Uinfo;
INSERT INTO Uinfo VALUES(null,10,5.6,70,'Female');
结果:-
显然 INSERT 没有插入数据。查看日志显示:-
create table Uinfo(id2 integer primary key AUTOINCREMENT not null,FOREIGN KEY (id2) REFERENCES calendar(id5))
> OK
> Time: 0.074s
SELECT * FROM Uinfo
> OK
> Time: 0s
INSERT INTO Uinfo VALUES(null,'Female')
> FOREIGN KEY constraint failed
> Time: 0s
所以添加了外键约束。
在测试 Android 应用程序中执行等效操作是使用以下代码进行的:-
public class MainActivity extends AppCompatActivity {
DatabaseHelper DBHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DBHelper = new DatabaseHelper(this);
SQLiteDatabase db = DBHelper.getWritableDatabase();
db.execSQL("INSERT INTO Uinfo VALUES(null,'Female')");
Log.d("DBINFO","After the first insert");
db.execSQL("PRAGMA foreign_keys = true");
db.execSQL("INSERT INTO Uinfo VALUES(null,"After the second insert");
}
}
结果:-
2021-04-24 15:34:27.954 5644-5644/a.a.so67224090javafknotshowing D/DBINFO: After the first insert
2021-04-24 15:34:27.955 5644-5644/a.a.so67224090javafknotshowing D/AndroidRuntime: Shutting down VM
2021-04-24 15:34:27.957 5644-5644/a.a.so67224090javafknotshowing E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.a.so67224090javafknotshowing,PID: 5644
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so67224090javafknotshowing/a.a.so67224090javafknotshowing.MainActivity}: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:748)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1770)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1698)
at a.a.so67224090javafknotshowing.MainActivity.onCreate(MainActivity.java:20)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
应用程序因异常而崩溃,异常消息为 FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
但是日志还包含D/DBINFO: After the first insert
。
即第一个 INSERT 没有导致异常,它是 THE IMPORTANT db.execSQL("PRAGMA foreign_keys = true");
如果没有这一行(或等效行),那么 Android 上的默认设置(与默认 SQLite 一样)是关闭外键处理。以上打开外键处理。
因此,如果您的问题更多的是外键什么都不做,那么这可能是原因。