Fethi Tekyaygil Fethi Tekyaygil - 2 months ago 23
C# Question

Entity Framework - DbSet Contains Null Entity

I'm tyring to add an entity to DbSet and save changes in context in Entity Framework Code First.I have University DbSet:

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


I have 5 class in use, Term,Faculty,Department,University and Student Classes.Their constructor methods are like:

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>();
}


I get Student entity from previous forms,(student which logged in the program).When I'm trying to add entities that filled by comboboxes and textboxes,I realized that Universities DbSet filling with the real entity that I meant to add but also filling with null University entity.My Id values not incrementing automatically so I'm incrementing them manual.My code:

Create Faculty Entity:

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();


Create Department Entity:

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();


Create Univresity Entity:

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);


Create Term Entity:

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;


And my DbSet Additions:

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


But I got Valdiation failed error so I used try catch blocks to analyze exception.I realized that my Universities DbSet contains null University entity .When I'm debugging,I realized that they're coming from entity creations that I make for the purpose of determining the ID of the entities.I tried to reach the null values in Universities DbSet and remove them but I couldn't do it in that way.The screenshot is below:

DbSet

Other DbSet's don't have that problem.I don't know what to do to get rid of that problem.Any helps would be appreciate.Thanks.

Answer

The answer possibly is in that you are adding the university once directly into the DbSet but then again through the relationship between faculties and the university.

When you add an entity to a context through DbSet.Add(entity) the entire graph of that entity gets attached to the underlying context with it and all entities in that graph are set to the Added state, except if the root entity is already Added. So then when you associate your Faculty, Term and Department with the University and then add all four to the context you get more than the one University you expected. I can't be 100% sure of what is going on because as you say you are manually generating the Id values and you haven't disclosed your entire model.

There are three ways I see you can solve this:

1: Change the relationship assignment to use the UniversityId on Faculty, Term and Department, or remove the assignment altogether and rely on the relationships as assigned by the collections:

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: Don't add the university to the context

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

3: The concept of an Aggregate Root in Domain Driven Design would deal to this by only adding the root entity through which the related entities are accessed.

Comments