Entity Framework should not be able to insert values for navigational properties.

c# entity-framework wpf

Question

Entity Framework 4.0 is being used by a WPF application I'm working on. A main key exception occurred when I attempted to save the object, however the primary key is an auto-incremented field, so I'm not sure why it occurred.

Following some trial-and-error, some debugging, and use of the SQL profiler, I discovered that since I had set the object's navigation attribute, a record had to be placed in the parent database before my object could be added.

The key question is if an effort is made to install an Employee object and establish its department as an Employee. A new record is then configured to be put on the department object when Department = deptObject.

Please provide me with a method, property, or anything else that will prevent navigational property objects from being added to the database.

Thanks

1
16
8/23/2016 12:03:49 PM

Accepted Answer

If detached entities are used improperly, EF behaves in this fashion. I assume you're using anything similar to this:

var employee = new Employee();
employee.Department = GetDepartmentFromSomewhere(departmentId);

...

using (var context = new YourContext())
{
    context.Employees.AddObject(employee);
    context.SaveChanges();
}

The employee entity was prepared by this code, which also created a reference to an existing department and saved a new employee to the database. What is the issue? The difficulty is thatAddObject not just includes the employee but the whole object graph. That is how EF works; you cannot have an object graph in which some items are contextually related while others are not.AddObject creates a new object for each item in the graph (new one = put into database). Therefore, you must either alter the order of your actions or manually update the status of entities so that your context recognizes the existence of the department.

Use the same context to load the department and save the employee as the first solution:

using (var context = new YourContext())
{
    var employee = new Employee();
    ...
    context.Employees.AddObject(employee);

    employee.Department = context.Departments.Single(d => d.Id == departmentId);
    context.SaveChanges();
}

The second option is to independently attach each entity to the context before making references between them:

var employee = new Employee();
...

var department = GetDepartmentFromSomewhere(departmentId);

using (var context = new YourContext())
{
    context.Employees.AddObject(employee);
    context.Departments.Attach(department);
    employee.Department = department;

    context.SaveChanges();
}

The department's condition should be corrected manually as a third option to prevent context from reinserting it:

var employee = new Employee();
employee.Department = GetDepartmentFromSomewhere(departmentId);

...

using (var context = new YourContext())
{
    context.Employees.AddObject(employee);
    context.ObjectStateManager.ChangeObjectState(employee.Department, 
                                                 EntityState.Unchanged);
    context.SaveChanges();
}
46
10/25/2011 8:32:46 AM

Popular Answer

In addition to the three options previously offered in Ladislav's excellent response, I would like to propose a fourth. In actuality, it is a more in-depth version of Naor's brief response. Version 6 of the Entity Framework is what I'm using.


Instead than using the department object, provide the employee the department id.

In my model classes, I usually have a "foreign key value" property in addition to the navigation property.

then on theEmployee class I possessDepartment property as well as anDepartmentId type int (if it's plausible that an int may be null, make the int nullable).Employee has noDepartment ):

public class Employee
{
    public int Id { get; set; }

    public String EmployeeName { get; set; }


    #region FK properties

    public Department Department { get; set; }

    public int? DepartmentId { get; set; }

    #endregion
}

What you might do right now is just set theDepartmentId thus as opposed to:

employee.Department = departmentObject;

simply set:

employee.DepartmentId = departmentObject.Id;

or

employee.DepartmentId = departmentid

when phoning nowSaveChanges On the newly added employee, no new department is established; just the employee is stored. However, the allusion toEmployee to Department is set appropriately as a result of the given department id.


More details

I would typically access theDepartment item of theEmployee just in class while reading or processing workers. I would utilize the to create or update employees using theDepartmentId possession of theEmployee class to put in.

excluding from theDepartment possession of theEmployee has one drawback: It can make debugging more difficult because before callingSaveChanges It would not be feasible to view or utilize the workers without going back and reading theDepartment item of theEmployee .


EF6 entity state information correction

This relates to Ladislav's third solution.

This is how it's done using EF6:

_context.Entry(employee.Department).State = EntityState.Unchanged;


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow