Entity Framework - DbSet содержит пустую сущность

Я тороплюсь добавить сущность в DbSet и сохранить изменения в контексте в Entity Framework Code First. У меня есть University DbSet:

public DbSet<University> Universities { get; set; }

У меня 5 класс в пользовании - Срок; Факультет; Отделение; Университет; и студент. Их методы конструктора похожи на:

public Student()
{
    Universities = new List<University>();
    User = new DATABASE.User();
    Terms = new List<Term>();
}
public University()
{
    UniversityFaculties = new List<Faculty>();
    UniversityDepartments = new List<Department>();
    Students = new List<Student>();
}
public Term()
{
    Students = new List<Student>();
    Lessons = new List<Lesson>();
    university = new University();
}
public Faculty()
{
    University = new University();
    Students = new List<Student>();
}
public Department()
{
    University = new University();
    Students = new List<Student>();
}

Я получаю объект "Студент" из предыдущих форм (студент, который вошел в программу). Когда я пытаюсь добавить сущности, заполненные полями со списком и текстовыми полями, я понял, что Universities DbSet заполняется реальной сущностью, которую я хотел добавить, но также заполняется пустой сущностью University. Мои значения Id не увеличиваются автоматически, поэтому я увеличиваю их вручную. Мой код:

Создать объект факультета:

Faculty f = entities.Faculties.OrderByDescending(o => o.FacultyId).FirstOrDefault();
int newFacultyId = (f == null ? 1 : f.FacultyId + 1);

var faculty = new Faculty();
faculty.FacultyId = newFacultyId;
faculty.FacultyName = FacultyComboBox2.SelectedItem.ToString();

Создать объект отдела:

Department d = entities.Departments.OrderByDescending(o =>o.DepartmentId).FirstOrDefault();
int newDepartmentId = (d == null ? 1 : d.DepartmentId + 1);

var department = new Department();
department.DepartmentId = newDepartmentId;
department.DepartmentName = DepartmentComboBox3.SelectedItem.ToString();

Создать университетскую сущность:

University uni = entities.Universities.OrderByDescending(o => o.UniversityId).FirstOrDefault();
int newUniId = (uni == null ? 1 : uni.UniversityId + 1);

var university = new University();

university.UniversityId = newUniId;
university.UniversityName = UniversityComboBox1.Text;

university.UniversityFaculties.Add(faculty);
university.UniversityDepartments.Add(department);
university.Students.Add(student);

student.Universities.Add(university);
faculty.University = university;
department.University = university;
faculty.Students.Add(student);
department.Students.Add(student);

Создать временную сущность:

Term t = entities.Terms.OrderByDescending(o => o.TermId).FirstOrDefault();
int newTermId = (t == null ? 1 : t.TermId + 1);

var term = new Term();

term.TermId = newTermId;
term.TermTerm = int.Parse(TermComboBox1.Text);
term.TermYear = int.Parse(YearComboBox1.Text);

term.Students.Add(student);
student.Terms.Add(term);
term.university = university;

И мои дополнения к DbSet:

   entities.Faculties.Add(faculty);
   entities.Departments.Add(department);
   entities.Universities.Add(university);
   entities.Terms.Add(term);
   entities.SaveChanges();

Но у меня возникла ошибка с ошибкой проверки, поэтому я использовал блоки try catch для анализа исключения. Я понял, что мой DbSet Universities содержит пустую сущность University. Когда я отлаживаю, я понял, что они исходят от созданий сущностей, которые я делаю с целью определения идентификаторов сущностей. Я попытался достичь нулевых значений в Universities DbSet и удалить их, но у меня не получилось этого сделать. Снимок экрана ниже:

DbSet

У других DbSet такой проблемы нет. Я не знаю, что делать, чтобы избавиться от этой проблемы. Любая помощь будет признательна. Спасибо.


person Fethi Tekyaygil    schedule 21.09.2016    source источник
comment
Ответ, возможно, заключается в том, что вы добавляете университет один раз непосредственно в DbSet, а затем снова через отношения между факультетами и университетом. Концепция агрегированного корня в доменно-ориентированном дизайне решает эту проблему, добавляя только корень, который неявно добавляет связанные сущности.   -  person strongbutgood    schedule 21.09.2016
comment
Конструкторы факультета, семестра и кафедры создают именно этот университет. Похоже, что некоторые из них не были установлены до тех пор, пока не были прикреплены эти объекты, попробуйте удалить эти назначения, поскольку вы все равно устанавливаете университет в целом.   -  person DevilSuichiro    schedule 21.09.2016
comment
Я это сделал! Я сделал, как сказал @DevilSuichiro. Я удалил назначения университетов, которые имеют место в конструкторах, и проблема решена! Спасибо за совет! Я изучу Aggragate Root в доменно-ориентированном дизайне, как только смогу. Спасибо за ваш комментарий и руководство strongbutgood   -  person Fethi Tekyaygil    schedule 22.09.2016


Ответы (1)


Ответ, возможно, заключается в том, что вы добавляете университет один раз непосредственно в DbSet, а затем снова через отношения между факультетами и университетом.

Когда вы добавляете сущность в контекст через DbSet.Add(entity), весь граф этой сущности присоединяется к базовому контексту вместе с ней, и все сущности в этом графе устанавливаются в состояние «Добавлено», за исключением случаев, когда корневая сущность уже добавлена. Итак, когда вы связываете свой факультет, семестр и кафедру с университетом, а затем добавляете все четыре в контекст, вы получаете больше, чем один университет, который вы ожидали. Я не могу быть на 100% уверен в том, что происходит, потому что, как вы говорите, вы вручную генерируете значения Id и не раскрыли всю свою модель.

Я считаю, что есть три способа решить эту проблему:

1: Измените назначение отношения, чтобы использовать UniversityId для факультета, срока и отдела, или полностью удалите назначение и полагайтесь на отношения, назначенные коллекциями:

uni = entities.Universities.OrderByDescending(o => o.UniversityId).FirstOrDefault();
int newUniId = (uni == null ? 1 : uni.UniversityId + 1);

var university = new University();
university.UniversityId = newUniId;
university.UniversityName = UniversityComboBox1.Text;

// these lines are sufficient to build the relationships between entities, you don't have to set both sides
university.UniversityFaculties.Add(faculty);
university.UniversityDepartments.Add(department);
university.Students.Add(student);

student.Universities.Add(university);
// use foreign key properties to build the relationship without having large graphs when adding to context
faculty.UniversityId = newUniId;
department.UniversityId = newUniId;

faculty.Students.Add(student);
department.Students.Add(student);

2. Не добавляйте университет в контекст

entities.Faculties.Add(faculty);
entities.Departments.Add(department);
// entities.Universities.Add(university);
entities.Terms.Add(term);
entities.SaveChanges();

3: Концепция агрегированного корня в доменно-ориентированном дизайне решает эту проблему, только добавляя корневой объект, через который осуществляется доступ к связанным объектам.

person strongbutgood    schedule 22.09.2016
comment
Это не совсем правда. оператор .Add добавит дерево к графу объекта (ChangeTracker, а не DbSet), если объект уже не находится в контексте. это сделано для того, чтобы избежать присоединения к DbSet нескольких объектов, которые фактически не присоединяют к ним свойства навигации. Кроме того, ваш ответ предлагает несколько источников соответствующих деревьев объектов, что сделает любой метод Save излишне сложным. - person DevilSuichiro; 23.09.2016
comment
@DevilSuichiro отмечает, что я обновлю, чтобы более точно прояснить, что происходит. - person strongbutgood; 23.09.2016