Платформа сущностей повторно вставляет ссылочные значения внешнего ключа - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть следующая структура сущности.

public class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        public class University
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        public class Subject
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        //A student may have to go many universities for the courses in the curriculum
        public class UniversityStudentAssociation
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public Student Student { get; set; }
            public University University { get; set; }
            public IEnumerable<Subject> Subjects { get; set; }
        }

Мои данные сущности такие же, как ниже. Студент должен решить, какой курс (ы) он должен выбрать и из какого университета.

Студент Роджер должен пройти два курса из Массачусетского технологического института и 2 курса из Гарварда

Эти данные получены со стороны клиента в качестве моделей представления и преобразования в сущности.


var universityStudentAssociations = new List<UniversityStudentAssociation>
            {
                //New association
                new UniversityStudentAssociation
                {
                    Id=0,
                    //Already existing student
                    Student=new Student
                    {
                        Id=1,
                        Name="Roger"
                    },
                    //Existing university
                    University= new University
                    {
                        Id=1,
                        Name="MIT"
                    },
                    Subjects=new List<Subject>
                    {
                        //Existing Subject
                        new Subject
                        {
                            Id=1,
                            Name="Psychology"
                        },
                        //Existing Subject
                        new Subject
                        {
                            Id=2,
                            Name="Sociology"
                        }
                    }
                },
                //New association
                new UniversityStudentAssociation
                {
                    Id=0,
                    //Already existing student
                    Student=new Student
                    {
                        Id=1,
                        Name="Roger"
                    },
                    //Existing university
                    University= new University
                    {
                        Id=2,
                        Name="Harvard"
                    },
                    Subjects=new List<Subject>
                    {
                        //Existing Subject
                        new Subject
                        {
                            Id=3,
                            Name="Physics"
                        },
                        //Existing Subject
                        new Subject
                        {
                            Id=4,
                            Name="Mathematics"
                        }
                    }
                }
            };

Структура сущностей при вставке данных предполагает наличие объекта студента (Роджера), Университета (MIT и Гарвард) и предметов (физика, математика, Психология и Социология) должны быть повторно вставлены. Но для этого нужно просто ссылаться на таблицы Student, University и Subjects как внешние ключи в таблице UniversityStudentAssociation.

Следовательно, каждый раз, когда я пытаюсь вставить вышеуказанные данные, среда Entity вставляет 2 новых студентов, 2 новых университета и 4 Предметы в соответствующих таблицах.

Пожалуйста, помогите мне, как я могу сказать Entity Framework ссылаться на существующие данные, а не вставлять новые данные.

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

Заранее спасибо.

1 Ответ

0 голосов
/ 14 февраля 2020

Важно понимать, что ваши DbSet<...> классы в вашем DbContext представляют таблицы в вашей базе данных.

Класс в DbSet<...> представляет одну строку в таблице, и отношения между этим строка и строки из других таблиц.

В структуре сущностей не виртуальные свойства представляют столбцы таблиц, виртуальные свойства представляют отношения между таблицами (один ко многим, много to-many)

Мне кажется, что существует связь один-ко-многим между Student и UniversityStudentAssociation: каждый студент имеет ноль или более ассоциаций UniversityStudent, и каждая ассоциация UniversityStudent принадлежит точно одному студенту, а именно Ученик, к которому относится свойство Student.

Аналогичным образом, между Университетом и Университетской Студенческой Ассоциацией существует однозначное отношение: каждый Университет имеет ноль или более Ассоциаций Университетских Студентов, и каждая Ассоциация Университетских Студентов принадлежит ровно одному Университету Например, университет, на который ссылается свойство University.

Из-за этих двух отношений «один ко многим» фактически существует отношение «многие ко многим» между студентом и университетом: каждый студент посещает ноль. или более университетов, и каждый университет обучает ноль или более студентов. Таблица UniversityStudentAssociation служит (расширенной) соединительной таблицей для реализации этого отношения «многие ко многим» (см. отношения «многие ко многим» )

Если вы следуете соглашениям о структуре сущностей Ваши занятия будут выглядеть следующим образом.

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    // every Student has zero or more UniversityStudentAssociations (one-to-many)
    public virtual ICollection<UniversityStudentAssociation> UniversityStudentAssociations {get; set;}
}

public class University
{
    public int Id { get; set; }
    public string Name { get; set; }

    // every University has zero or more UniversityStudentAssociations (one-to-many)
    public virtual ICollection<UniversityStudentAssociation> UniversityStudentAssociations {get; set;}
}

Класс UniversityStudentAssociation:

public class UniversityStudentAssociation
{
    public int Id { get; set; }
    public string Name { get; set; } 

    // Every UniversityStudentAssociation belongs to exactly one Student, using foreign key
    public int StudentId {get; set; }
    public virtual Student Student { get; set; }

    // Every UniversityStudentAssociation belongs to exactly one University, using foreign key
    public int UniversityId {get; set; }
    public virtual University University { get; set; }

    // Every UniversityStudentAssociation has zero or more Subjects (one-to-many)
    public IEnumerable<Subject> Subjects { get; set; }
}

И, наконец, предметный класс:

public class Subject
{
    public int Id { get; set; }
    public string Name { get; set; }

    // every Subject belongs to exactly one UniversityStudentAssociation using foreign key
    public int UniversityStudentAssociationId {get; set; }
    public virtual UniversityStudentAssociation UniversityStudentAssociation {get; set;}
}

Обратите внимание, что я добавил виртуальные члены для информирования структуры сущностей об отношениях между таблицами. Поскольку одна сторона имеет виртуальную коллекцию ICollection <...>, а другая - один виртуальный элемент, структура сущностей знает, что это отношение один ко многим.

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

Обычно, если вы хотите "получить элементы с (некоторыми или всеми) их подэлементами, вы можете использовать Коллекции:

Дайте мне (некоторые свойства) всех студентов, которые живут в Нью-Йорке и (некоторые свойства) всех университетов, которые они посещают

var result = dbContext.Students
    .Where(student => student.City == "New York)
    .Select(student => new
    {
        // Select only the Student properties that you plan to use:
        Id = student.Id,
        Name = student.Name,
        ...

        Universities = student.UniversityStudentAssociations
            .Select(association => new
        {
            // I only want the university properties
            // again: only the properties that you plan to use:
            UniversityId = association.University.Id,
            UniversityName = association.University.Name,
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...