Проблема с синтаксисом внешнего ключа SQLite с использованием списочных представлений для извлечения данных - PullRequest
0 голосов
/ 04 апреля 2019

Это контекст.У меня есть помощник базы данных, который создает 3 таблицы в одной базе данных.Две из этих таблиц имеют внешние ключи.Все работало, все было хорошо, но, учитывая то, что я хотел сделать, мне нужно было использовать списочные просмотры вместо текстовых, чтобы отображать мои данные и иметь возможность редактировать, удалять и т. Д. По какой-то причине просмотры списков на Android отличаются от других языков программирования.Я разобрался с адаптерами и всякой ерундой.Моя новая проблема заключалась в том, что мое приложение не отображало данные, и когда я проверял свою logcat, я получил это сообщение

 Caused by: java.lang.IllegalArgumentException: column '_id' does not exist. Available columns: [id, termName, termStart, termEnd]

Это было для одной таблицы с именем 'term_table'.Поэтому я изменил идентификатор с «id» на «_id», и это помогло.

Так что все хорошо, хорошо?Нет, потому что две другие таблицы имеют свои собственные идентификаторы и внешние ключи.Когда я выполнил один и тот же запрос для другой таблицы с именем «assign_table», я получил ту же ошибку, поэтому я изменил «id» на «_id».Проблема заключается в том, что «courses_table» (третья таблица) использует «_id» в качестве внешнего ключа для ссылки на таблицу «term_table».Таким образом, я получаю сообщение об ошибке, сообщающее, что я создавал дублирующиеся столбцы - первичный ключ _id и внешний ключ _id для ссылки на term_table.

Я переименовываю id для courses_table из _id вcourses_id.Теперь я возвращаюсь к исходной точке, получая ту же ошибку:

 Caused by: java.lang.IllegalArgumentException: column '_id' does not exist. Available columns: [assess_id, assessName, assessDueDate, assessType, courses_id]

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

Это мои 3 таблицы в моей базе данныхhelper

//terms table
   public static final String TERM_TABLE_NAME = "term_table";
   public static final String COL_TERM1 = "_id";
   public static final String COL_TERM2 = "termName";
   public static final String COL_TERM3 = "termStart";
   public static final String COL_TERM4 = "termEnd";
   public static final String TERM_DATABASE_NAME = "term.db";
   //courses table
   public static final String COURSES_TABLE_NAME = "courses_table";
   public static final String COL_COURSE1 = "courses_id";
   public static final String COL_COURSE2 = "courseTitle";
   public static final String COL_COURSE3 = "courseStartDate";
   public static final String COL_COURSE4 = "courseEndDate";
   public static final String COL_COURSE5 = "courseStatus";
   public static final String COL_COURSE6 = "optionalNote";
   public static final String COL_COURSE7 = "mentorName";
   public static final String COL_COURSE8 = "mentorPhone";
   public static final String COL_COURSE9 = "mentorEmail";
   public static final String COL_COURSE_TERMID = "_id";
   //assess table
   public static final String ASSESS_TABLE_NAME = "assess_table";
   public static final String COL_ASSESS1 = "assess_id";
   public static final String COL_ASSESS2 = "assessName";
   public static final String COL_ASSESS3 = "assessDueDate";
   public static final String COL_ASSESS4 = "assessType";
   public static final String COL_ASSESS_COURSEID = "courses_id";

Это синтаксис создания

public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + TERM_TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, termName TEXT, termStart TEXT, termEnd TEXT)");
        db.execSQL("CREATE TABLE " + COURSES_TABLE_NAME + " (courses_id INTEGER PRIMARY KEY AUTOINCREMENT, courseTitle TEXT, courseStartDate TEXT, courseEndDate TEXT, courseStatus INTEGER, optionalNote TEXT, mentorName TEXT, mentorPhone TEXT, mentorEmail TEXT, _id INTEGER, FOREIGN KEY (_id) REFERENCES term_table(_id))");
        db.execSQL("CREATE TABLE " + ASSESS_TABLE_NAME + " (assess_id INTEGER PRIMARY KEY AUTOINCREMENT, assessName TEXT, assessDueDate TEXT, assessType INTEGER, courses_id INTEGER, FOREIGN KEY (courses_id) REFERENCES courses_table(courses_id))");
    }

Ответы [ 2 ]

1 голос
/ 04 апреля 2019

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

Они не должны быть такими, как вы могли бы использовать AS _id для динамического создания столбца с псевдонимом (обратите внимание, что * у вас есть id , а также _id столбец) например

SELECT *, id AS _id
  • вам может понадобиться только 1 _id столбец для CursorAdapter.

Что касается определения внешнего ключа с использованием

INTEGER PRIMARY KEY _id,....., FOREIGN KEY(_id) REFERENCES parent_table(column_in_parent_table)

это, вероятно, НЕ будет работать последовательно / хорошо / с пользой.

Вы фактически говорите, что столбец _id должен быть значением в родительской таблице. Таким образом, вы ограничиваете отношение 1-1, поскольку INTEGER PRIMARY KEY неявно уникально, так как это псевдоним обычно скрытого столбца rowid , значение, поскольку столбец является специальным, ДОЛЖЕН также быть целым числом .

например. если первая строка таблицы курсов ссылается на столбец со значением 1, то отлично (скажем, TERM1), тогда в этой таблице не может быть другой ссылки на TERM1, поскольку _id НЕ ДОЛЖЕН быть 1.

  • Таким образом, уникальное ограничение (дубликаты), с которым вы столкнулись.

Короче говоря, вы должны ссылаться на столбец _id в качестве столбца родительской таблицы внешнего ключа (в вашем случае), но не использовать столбец _id в дочерней таблице в качестве столбец, который ссылается на родительскую таблицу, поскольку вы ограничиваете родительский элемент только одним дочерним элементом для этого значения, отношение 1-1 (что фактически означает, что две таблицы являются избыточными).

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

Как таковой вы хотите что-то вроде: -

public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + TERM_TABLE_NAME + " (_id INTEGER PRIMARY KEY, termName TEXT, termStart TEXT, termEnd TEXT)");
        db.execSQL("CREATE TABLE " + COURSES_TABLE_NAME + " (_id INTEGER PRIMARY KEY, courseTitle TEXT, courseStartDate TEXT, courseEndDate TEXT, courseStatus INTEGER, optionalNote TEXT, mentorName TEXT, mentorPhone TEXT, mentorEmail TEXT, course_term_reference INTEGER REFERENCES term_table(_id))");
        db.execSQL("CREATE TABLE " + ASSESS_TABLE_NAME + " (_id INTEGER PRIMARY KEY, assessName TEXT, assessDueDate TEXT, assessType INTEGER, assess_course_reference INTEGER REFERENCES courses_table(_id))");
}
  • Примечание AUTOINCREMENT был удален, вам не нужно ни это, ни накладные расходы, которые он несет SQLite Autoincrement согласно: -
  • Ключевое слово AUTOINCREMENT накладывает дополнительный процессор, память, дисковое пространство и издержки дискового ввода-вывода, и их следует избегать, если в этом нет особой необходимости. это обычно не требуется.
  • Были использованы более простые и, возможно, более понятные определения внешнего ключа столбца (т.е. внешние ключи были определены на уровне определения столбца, а не на уровне определения таблицы)

Однако я бы рекомендовал кодировать идентификаторы (имена столбцов, имена таблиц и т. Д.) Один раз как константы, а затем всегда ссылаться на эти константы.

Как таковой, я бы предложил, что выше было бы лучше, как: -

public static final String TERM_TABLE_NAME = "term_table";
public static final String COL_TERM1 = "_id";
public static final String COL_TERM2 = "termName";
public static final String COL_TERM3 = "termStart";
public static final String COL_TERM4 = "termEnd";
public static final String TERM_DATABASE_NAME = "term.db";
public static final int DBVERSION = 1;
//courses table
public static final String COURSES_TABLE_NAME = "courses_table";
public static final String COL_COURSE1 = "_id";
public static final String COL_COURSE2 = "courseTitle";
public static final String COL_COURSE3 = "courseStartDate";
public static final String COL_COURSE4 = "courseEndDate";
public static final String COL_COURSE5 = "courseStatus";
public static final String COL_COURSE6 = "optionalNote";
public static final String COL_COURSE7 = "mentorName";
public static final String COL_COURSE8 = "mentorPhone";
public static final String COL_COURSE9 = "mentorEmail";
public static final String COL_COURSE_TERM_REFERENCE = "term_reference";
//assess table
public static final String ASSESS_TABLE_NAME = "assess_table";
public static final String COL_ASSESS1 = "_id";
public static final String COL_ASSESS2 = "assessName";
public static final String COL_ASSESS3 = "assessDueDate";
public static final String COL_ASSESS4 = "assessType";
public static final String COL_ASSESS_COURSE_REFERENCE = "course_reference";

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(
            "CREATE TABLE " + TERM_TABLE_NAME + "(" +
                    COL_TERM1 + " INTEGER PRIMARY KEY," +
                    COL_TERM2 + " TEXT, " +
                    COL_TERM3 + " TEXT, " +
                    COL_TERM4 + " TEXT" +
                    ")"
    );
    db.execSQL(
            "CREATE TABLE " + COURSES_TABLE_NAME + "(" +
                    COL_COURSE1 + " INTEGER PRIMARY KEY, " +
                    COL_COURSE2 + " TEXT, " +
                    COL_COURSE3 + " TEXT, " +
                    COL_COURSE4 + " TEXT, " +
                    COL_COURSE5 + " INTEGER, " +
                    COL_COURSE6 + " TEXT, " +
                    COL_COURSE7 + " TEXT, " +
                    COL_COURSE8 + " TEXT, " +
                    COL_COURSE9 + " TEXT, " +
                    COL_COURSE_TERM_REFERENCE + "INTEGER REFERENCES " + TERM_TABLE_NAME + "(" + COL_TERM1 + ")" +
                    ")"
    );

    db.execSQL(
            "CREATE TABLE " + ASSESS_TABLE_NAME + "(" +
                    COL_ASSESS1 + " INTEGER PRIMARY KEY, " +
                    COL_ASSESS2 + " TEXT, " +
                    COL_ASSESS3 + " TEXT, " +
                    COL_ASSESS4 + " INTEGER, " +
                    COL_ASSESS_COURSE_REFERENCE + " INTEGER REFERENCES " + COURSES_TABLE_NAME + "(" + COL_COURSE1 + ")" +
                    ")"
    );
}

Приведенный выше результат в SQL (для каждой таблицы) выглядит так: -

CREATE TABLE term_table(_id INTEGER PRIMARY KEY,termName TEXT, termStart TEXT, termEnd TEXT)
CREATE TABLE courses_table(courses_id INTEGER PRIMARY KEY, courseTitle TEXT, courseStartDate TEXT, courseEndDate TEXT, courseStatus INTEGER, optionalNote TEXT, mentorName TEXT, mentorPhone TEXT, mentorEmail TEXT, term_reference INTEGER REFERENCES term_table(_id))
CREATE TABLE assess_table(assess_id INTEGER PRIMARY KEY, assessName TEXT, assessDueDate TEXT, assessType INTEGER, course_reference INTEGER REFERENCES courses_table(courses_id))

Дополнительный

Чтобы использовать поддержку внешнего ключа, его необходимо включить. Таким образом, вы можете переопределить метод onConfigure помощника базы данных, чтобы включить поддержку, например. : -

@Override
public void onConfigure(SQLiteDatabase db) {
    super.onConfigure(db);
    db.setForeignKeyConstraintsEnabled(true);
}
1 голос
/ 04 апреля 2019

переименуйте первичные и внешние ключи следующим образом:

public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + TERM_TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, termName TEXT, termStart TEXT, termEnd TEXT)");
        db.execSQL("CREATE TABLE " + COURSES_TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, courseTitle TEXT, courseStartDate TEXT, courseEndDate TEXT, courseStatus INTEGER, optionalNote TEXT, mentorName TEXT, mentorPhone TEXT, mentorEmail TEXT, for_cors_term INTEGER, FOREIGN KEY (for_cors_term) REFERENCES term_table(_id))");
        db.execSQL("CREATE TABLE " + ASSESS_TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, assessName TEXT, assessDueDate TEXT, assessType INTEGER, for_ases_cors INTEGER, FOREIGN KEY (for_ases_cors) REFERENCES courses_table(_id))");
    }

   public static final String TERM_DATABASE_NAME = "term.db";

   //terms table
   public static final String TERM_TABLE_NAME = "term_table";
   public static final String COL_TERM1 = "_id"; //primary key
   public static final String COL_TERM2 = "termName";
   public static final String COL_TERM3 = "termStart";
   public static final String COL_TERM4 = "termEnd";

   //courses table
   public static final String COURSES_TABLE_NAME = "courses_table";
   public static final String COL_COURSE1 = "_id"; //primary key
   public static final String COL_COURSE2 = "courseTitle";
   public static final String COL_COURSE3 = "courseStartDate";
   public static final String COL_COURSE4 = "courseEndDate";
   public static final String COL_COURSE5 = "courseStatus";
   public static final String COL_COURSE6 = "optionalNote";
   public static final String COL_COURSE7 = "mentorName";
   public static final String COL_COURSE8 = "mentorPhone";
   public static final String COL_COURSE9 = "mentorEmail";
   public static final String COL_COURSE_TERMID = "for_cors_term"; //foreign key

   //assess table
   public static final String ASSESS_TABLE_NAME = "assess_table";
   public static final String COL_ASSESS1 = "_id"; //primary key
   public static final String COL_ASSESS2 = "assessName";
   public static final String COL_ASSESS3 = "assessDueDate";
   public static final String COL_ASSESS4 = "assessType";
   public static final String COL_ASSESS_COURSEID = "for_ases_cors"; //foreign key

Или, если вы не хотите использовать поле _id в качестве первичного ключа, вы можете использовать RecyclerView вместо ListView

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