соединение двух таблиц с внешними ключами в sqlite - PullRequest
1 голос
/ 28 октября 2019

Привет, в моем senario есть таблица с 4 столбцами, и я пытаюсь создать другую таблицу с подключением к первой таблице, но я не понимаю, почему я получаю эту ошибку в logcat

2019-10-28 01:04:00.853 29812-29812/com.test.fastfoodfinder E/SQLiteDatabase: Error inserting notes_main=testeststststststststs
    android.database.sqlite.SQLiteException: no such table: notes (code 1 SQLITE_ERROR): , while compiling: INSERT INTO notes(notes_main) VALUES (?)

, поэтому я создалкласс для моей базы данных, и это то, что я сделал

public class RestaurantDBHelper extends SQLiteOpenHelper {

    private final static String DATABASE_NAME = "FastFood_DataBase.db";
    private final static int DATABASE_VERSION = 1;



    private final static String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
            "(" + COLUMN_RESTAURANT_ID + " INTEGER PRIMARY KEY ," +
            COLUMN_RESTAURANT_NAME + " TEXT, " +
            COLUMN_RESTAURANT_ADDRESS + " TEXT, " +
            COLUMN_RESTAURANT_TYPE + " INTEGER, " +
            COLUMN_RESTAURANT_IMAGE + " INTEGER);";


    private final static String CREATE_TABLE_NOTES = "CREATE TABLE " + TABLE_NAME_NOTES +
            "(" + COLUMN_NOTES_ID + " INTEGER PRIMARY KEY, "
            + COLUMN_NOTES + " TEXT," + "FOREIGN KEY (" + COLUMN_NOTES_ID + ") REFERENCES " + TABLE_NAME +"(restaurant_id) ON DELETE CASCADE)";


    public final static String DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;

    public RestaurantDBHelper(@Nullable Context context){
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("PRAGMA FOREIGN_KEYS = ON;");
        db.execSQL(CREATE_TABLE);
        db.execSQL(CREATE_TABLE_NOTES);
    }


    @Override
    public void  onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(DELETE_TABLE);
        onCreate(db);
    }

    public void addRestaurant(Restaurant restaurant) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();

        values.put(COLUMN_RESTAURANT_NAME, restaurant.getName());
        values.put(COLUMN_RESTAURANT_ADDRESS, restaurant.getAddress());
        values.put(COLUMN_RESTAURANT_TYPE,restaurant.getType());
        values.put(COLUMN_RESTAURANT_IMAGE, restaurant.getType());

        db.insert(TABLE_NAME, null, values);

        db.close();
    }

    public void addNotes (Restaurant restaurant) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();

        values.put(COLUMN_NOTES,restaurant.getNote());

        db.insert(TABLE_NAME_NOTES,null,values);

        db.close();
    }

и

public class RestaurantContract {
    public static class EntryRestaurants {
        public final static String TABLE_NAME = "restaurants";
        public final static String COLUMN_RESTAURANT_ID = "restaurant_id";
        public final static String COLUMN_RESTAURANT_NAME = "restaurant_name";
        public final static String COLUMN_RESTAURANT_ADDRESS = "restaurant_address";
        public final static String COLUMN_RESTAURANT_TYPE = "restaurant_type";
        public final static String COLUMN_RESTAURANT_IMAGE = "restaurant_image_type";
        public final static String COLUMN_RESTAURANT_NOTE_ID = "note_id";

        public final static String TABLE_NAME_NOTES = "notes";
        public final static String COLUMN_NOTES_ID = "notes_id";
        public final static String COLUMN_NOTES = "notes_main";

        public final static int RESTAURANT_TYPE_DELIVERY = 1;
        public final static int RESTAURANT_TYPE_SITDOWN = 2;
        public final static int RESTAURANT_TYPE_TAKEAWAY = 3;
    }
}

Я новый в Android, поэтому любая помощь будет оценена, спасибо

Ответы [ 2 ]

0 голосов
/ 28 октября 2019

Я считаю, что ваша проблема связана с методом onCreate . Он работает ТОЛЬКО при создании базы данных, он не запускается при каждом запуске приложения.

Самое простое решение, при условии, что вам не нужно хранить какие-либо существующие данные, - это либо удалить данные приложения, либо удалить приложение. После выполнения любого из них снова запустите приложение, и новая таблица будет создана при запуске метода onCreate .

Более того, бесполезно включать FOREIGN KEYS в методе onCreate. ИНОСТРАННЫЕ КЛЮЧИ должны быть включены при каждом запуске приложения. Чтобы исправить это, переопределите метод onConfigure , а затем используйте db.setForeignKeyConstraintsEnabled(true);

  • , это просто удобная альтернатива использованию db.execSQL("PRAGMA FOREIGN_KEYS = ON;");, поэтому, если вы предпочитаете, вы можете использовать это припереопределяя метод onConfigure.

например, добавьте этот метод в класс RestaurantDBHelper: -

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

Однако , у вас возникнут проблемы при попытке добавитьзаметки, поскольку дочерний элемент будет установлен на ноль, и, следовательно, они не будут связью / картой / ассоциацией / ссылкой между добавленной заметкой и рестораном.

Вам необходимо использовать что-то вроде: -

public long addNote(String note, long restaurantId) {
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(COLUMN_NOTES,note);
    values.put(COLUMN_NOTES_ID,restaurantId);
    return db.insert(TABLE_NAME_NOTES,null,values);
}

НО тогда у вас может возникнуть проблема с определением идентификатора ресторана.

НО тогда вы можете столкнуться с еще одной проблемой в этомВы можете иметь только одну заметку на ресторан, так как столбец, используемый для ссылки на ресторан, определен как INTEGER PRIMARY KEY и, следовательно, является столбцом UNIQUE (одно и то же значение можно использовать только один раз (исключение - ноль, поскольку ноль - cсчитается уникальным для другого нулевого значения)).

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

Если вы хотите, чтобы в ресторане было несколько примечаний ( отношение один ко многим ), то вам не следует делать столбец INTEGER PRIMARY KEY, INTEGER будет достаточно,Тогда несколько заметок могут ссылаться на один и тот же ресторан.

Если вы хотите, чтобы заметка могла быть применена к нескольким ресторанам, вы бы использовали третью таблицу сопоставления / строки / ссылки / ассоциативные (другое имя, вероятно, также существует). Такая таблица будет иметь две колонки, одна для ссылки на ресторан, а другая для ссылки на заметку. Тогда у вас будет отношение много ко многим между ресторанами и примечаниями (примечание может использоваться многими ресторанами, а ресторан может использовать много примечаний).

Вы можете найти The3 типа отношений в разработке базы данных полезно.

0 голосов
/ 28 октября 2019

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

https://sqlite.org/foreignkeys.html#fk_indexes

говорит

Еслисхема базы данных содержит ошибки внешнего ключа, для определения которых требуется более одного определения таблицы, тогда эти ошибки не обнаруживаются при создании таблиц. Вместо этого такие ошибки не позволяют приложению подготовить операторы SQL, которые изменяют содержимое дочерних или родительских таблиц способами, использующими внешние ключи. Ошибки, сообщаемые при изменении содержимого, представляют собой «ошибки DML», а ошибки, сообщаемые при изменении схемы, - «Ошибки DDL». Таким образом, другими словами, неправильно настроенные ограничения внешнего ключа, которые требуют рассмотрения как дочернего, так и родительского, являются ошибками DML. Сообщение об ошибке на английском языке для ошибок DML внешнего ключа обычно является «несоответствием внешнего ключа», но также может быть «нет такой таблицы», если родительская таблица не существует. Ошибки DML внешнего ключа выдаются, если:

The parent table does not exist, or
The parent key columns named in the foreign key constraint do not exist, or
The parent key columns named in the foreign key constraint are not the primary key of the parent table and are not subject to a unique constraint using collating sequence specified in the CREATE TABLE, or
The child table references the primary key of the parent without specifying the primary key columns and the number of primary key columns in the parent do not match the number of child key columns. 

Если вы никогда не дадите значение restaurant_id при вставке ресторана, тогда первичный ключ restaurants, вероятно, всегда будет null и, следовательно, не уникален

(Да, согласно https://www.sqlitetutorial.net/sqlite-primary-key/, чтобы сделать текущую версию SQLite совместимой с более ранней версией, SQLite позволяет столбцу первичного ключа содержать значения NULL.)

Таким образом, я бы сказал, что решение заключается в создании restaurant записей с уникальным значением первичного ключа при вставке ресторана или получении базы данных для генерации уникального значения при создании таблицы restaurant со строкой: -

private final static String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + COLUMN_RESTAURANT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + ....

Один из способов подтвердить это - загрузить FastFood_DataBase.* файлы, используя Device Explorer, в каталог базы данных вашего приложения, а затем открыть его в https://sqlitebrowser.org/ на вашем компьютере, чтобы подтвердитьсодержание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...