Как создать дочерний объект до создания родительского объекта? Могу ли я обойти ограничения внешнего ключа? - PullRequest
0 голосов
/ 31 мая 2019

У меня есть три таблицы: срок, курс и оценка. Термин является родителем курса, а курс является родителем оценки. Когда я создаю курс, есть список всех существующих терминов. Пользователь нажимает на термин, от которого он хочет отделить этот курс, и вставляется внешний ключ, который эквивалентен идентификатору выбранного термина. Это прекрасно работает без ограничений внешнего ключа. Когда я включаю ограничения внешнего ключа, я не могу создать курс, если термин не существует, или оценку, если курс не существует. Очевидно, что если пользователь сначала создает термин, а затем - курс, то при оценке все работает, но это не практично. Могу ли я не включать внешние ключи при возможности создать дочерний элемент перед родительским?

Здесь я создаю свои таблицы


@Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table " + TermDbSchema.TermTable.NAME + "(" +
                "_id integer primary key autoincrement, " +
                TermDbSchema.TermTable.Cols.UUID + ", " +
                TermDbSchema.TermTable.Cols.TITLE + ", " +
                TermDbSchema.TermTable.Cols.START_DATE + ", " +
                TermDbSchema.TermTable.Cols.END_DATE +
                ")"
        );
        db.execSQL("create table " + TermDbSchema.CourseTable.NAME + "(" +
                "_id integer primary key autoincrement, " +
                TermDbSchema.CourseTable.Cols.UUID + ", " +
                TermDbSchema.CourseTable.Cols.TITLE + ", " +
                TermDbSchema.CourseTable.Cols.START_DATE + ", " +
                TermDbSchema.CourseTable.Cols.END_DATE + ", " +
                TermDbSchema.CourseTable.Cols.CHOSEN_START_DATE + ", " +
                TermDbSchema.CourseTable.Cols.CHOSEN_END_DATE + ", " +

                TermDbSchema.CourseTable.Cols.COURSE_STATUS + ", " +
                TermDbSchema.CourseTable.Cols.OPTIONAL_NOTE + ", " +
                TermDbSchema.CourseTable.Cols.MENTOR_NAME + ", " +
                TermDbSchema.CourseTable.Cols.MENTOR_PHONE + ", " +
                TermDbSchema.CourseTable.Cols.MENTOR_EMAIL + ", " +
//this foreign key references TermTable
                TermDbSchema.CourseTable.Cols.COL_COURSE_TERM_REFERENCE + " INTEGER REFERENCES " + TermDbSchema.TermTable.NAME + "(_id) ON DELETE CASCADE ON UPDATE CASCADE" + //<<<<<<<<<< ADDED
                ")"
        );
        db.execSQL("create table " + TermDbSchema.AssessmentTable.NAME + "(" +
                "_id integer primary key autoincrement, " +
                TermDbSchema.AssessmentTable.Cols.UUID + ", " +
                TermDbSchema.AssessmentTable.Cols.TITLE + ", " +
                TermDbSchema.AssessmentTable.Cols.ASSESS_TYPE + ", " +
                TermDbSchema.AssessmentTable.Cols.DUE_DATE + ", " +
                TermDbSchema.AssessmentTable.Cols.GOAL_DATE + ", " +
//this foreign key references CourseTable
                TermDbSchema.AssessmentTable.Cols.COL_ASSESS_COURSE_REFERENCE + " INTEGER REFERENCES " + TermDbSchema.CourseTable.NAME + "(_id) ON DELETE CASCADE ON UPDATE CASCADE" + //<<<<<<<<<< ADDED
                //"course_reference" + " INTEGER REFERENCES " + "courses" + "(_id) ON DELETE CASCADE ON UPDATE CASCADE" +
                ")"
        );
    }

Вот моя схема таблиц:


public class TermDbSchema {
    public static final class TermTable {
        public static final String NAME = "terms";
        public static final class Cols {
            public static final String UUID = "uuid";
            public static final String TITLE = "title";
            public static final String START_DATE = "startdate";
            public static final String END_DATE = "enddate";

        }
    }
    public static final class CourseTable {
        public static final String NAME = "courses";
        public static final class Cols {
            public static final String UUID = "uuid";
            public static final String TITLE = "title";
            public static final String START_DATE = "startdate";
            public static final String END_DATE = "enddate";
            public static final String CHOSEN_START_DATE = "chosenstartdate";
            public static final String CHOSEN_END_DATE = "chosenenddate";

            public static final String COURSE_STATUS = "coursestatus";
            public static final String OPTIONAL_NOTE = "optionalnote";
            public static final String MENTOR_NAME = "mentorname";
            public static final String MENTOR_PHONE = "mentorphone";
            public static final String MENTOR_EMAIL = "mentoremail";
            public static final String COL_COURSE_TERM_REFERENCE = "term_reference";

        }
    }
    public static final class AssessmentTable {
        public static final String NAME = "assessments";
        public static final class Cols {
            public static final String UUID = "uuid";
            public static final String TITLE = "title";
            public static final String ASSESS_TYPE = "assesstype";

            public static final String DUE_DATE = "duedate";
            public static final String GOAL_DATE = "goaldate";
           public static final String COL_ASSESS_COURSE_REFERENCE = "course_reference";
        }
    }
}

Вот мой код, в который я вставляю значения в созданный объект Course.


private static ContentValues getContentValues(Course course) {
        ContentValues values = new ContentValues();
        values.put(CourseTable.Cols.UUID, course.getID().toString());
        values.put(CourseTable.Cols.TITLE, course.getTitle());
        values.put(CourseTable.Cols.START_DATE, course.getStartDate().getTime());
        values.put(CourseTable.Cols.END_DATE, course.getEndDate().getTime());
        values.put(CourseTable.Cols.CHOSEN_START_DATE, course.getChosenStartDate());
        values.put(CourseTable.Cols.CHOSEN_END_DATE, course.getChosenEndDate());

        values.put(CourseTable.Cols.COURSE_STATUS, course.getCourseStatus());
        values.put(CourseTable.Cols.OPTIONAL_NOTE, course.getCourseNote());
        values.put(CourseTable.Cols.MENTOR_NAME, course.getCourseMentorName());
        values.put(CourseTable.Cols.MENTOR_PHONE, course.getCourseMentorPhone());
        values.put(CourseTable.Cols.MENTOR_EMAIL, course.getCourseMentorEmail());

Это вставляет внешний ключ, который соответствует первичный ключ термина, который хочет пользователь этот курс, чтобы быть в стороне от


        values.put(CourseTable.Cols.COL_COURSE_TERM_REFERENCE, course.getTermReference()); 
        return values;
    }

1 Ответ

1 голос
/ 31 мая 2019

Можно ли обойти ограничения внешнего ключа?

Да,

1. Просто не добавляйте ограничение ForeignKey.

2. Используйте NULL

Пока NOT NULL не указан, установите значение NULL.

например. рассмотрим: -

DROP TABLE IF EXISTS course;
DROP TABLE IF EXISTS term;
CREATE TABLE IF NOT EXISTS term (id INTEGER PRIMARY KEY, termname TEXT);
INSERT INTO TERM (termname) VALUES ('Term001'),('Term002');
CREATE TABLE IF NOT EXISTS course (id INTEGER PRIMARY KEY, coursename TEXT, term_ref INTEGER REFERENCES term(id));
INSERT INTO course (coursename, term_ref) VALUES ('Course001',1),('Course002',2),('Course003',null);
SELECT * FROM course;

, что приводит к: -

enter image description here

т.е. Course003 не имеет связанной / сопоставленной записи в таблице терминов (в SQLite NULL считается уникальным)

3. DEFERRED

Вероятно, нецелесообразно использовать DEFERRABLE INITIALLY DEFERRED НО ограничение будет применяться при фиксации и может использоваться только для явной транзакции, т.е. вам нужно будет добавить термин перед фиксацией курса (следовательно, почему это было бы непрактично)

4 Промежуточный стол

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

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

...