Почему мои внешние ключи не отображаются, когда я просматриваю свою базу данных в браузере баз данных? Я неправильно их ввел?

#sqlite #android-studio #foreign-keys #android-sqlite

Вопрос:

     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"
 

перед первой строкой внешнего ключа, и это заставило базу данных прекратить запись данных в эту таблицу. Я обновил версию базы данных, чтобы посмотреть, будет ли это тоже иметь значение, но безрезультатно.
Я называю это неправильно? Возможно, мне просто не хватает правильного способа записи в столбце, в который входит внешний ключ. Хотя я не уверен, как это будет вставлено правильно.

Ответ №1:

Я полагаю, что ваша проблема заключается в непонимании того, что делает предложение FOREIGN KEY…..

Он не создает столбец для хранения внешнего ключа. Скорее, он добавляет ограничение (правило), которое гласит, что столбцы в создаваемой таблице ДОЛЖНЫ содержать существующее значение в таблице(столбцах), указанных после ССЫЛОК.

Утверждения верны и на самом деле создают ограничения внешнего ключа; как будет показано ниже.

Рассмотрим следующее (выполняется путем запуска кода с помощью Android Studio, который вы предоставили (плюс код, чтобы сделать его пригодным для использования), и, таким образом, создается база данных и необходимые таблицы)

  • использование ОТЛАДКИ для остановки при создании таблицы Uinfo (а также других таблиц) и копировании значения из переменной TABLE2_CREATE, полученное значение :-
    • 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 , 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));


SELECT * FROM Uinfo;
INSERT INTO Uinfo VALUES(null,10,5.6,70,'Female');
 

Результаты в :-

введите описание изображения здесь

Очевидно, что ВСТАВКА не вставляла данные. Взгляд на журнал показывает:-

 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))
> OK
> Time: 0.074s


SELECT * FROM Uinfo
> OK
> Time: 0s


INSERT INTO Uinfo VALUES(null,10,5.6,70,'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,10,5.6,70,'Female')");
        Log.d("DBINFO","After the first insert");
        db.execSQL("PRAGMA foreign_keys = true");
        db.execSQL("INSERT INTO Uinfo VALUES(null,10,5.6,70,'Female')");
        Log.d("DBINFO","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 .

т. е. первая ВСТАВКА не вызвала исключения, она была второй после ВАЖНОЙ db.execSQL("PRAGMA foreign_keys = true");

Без этой строки (или эквивалента) по умолчанию в Android (как и в SQLite по умолчанию) обработка внешних ключей отключена. Вышесказанное включает обработку внешнего ключа.

Так что, если ваша проблема в том, что внешние ключи ничего не делают, то это может быть причиной.