Saving dependent record without creating a duplicate principal record

筅森魡賤 提交于 2019-12-11 08:46:10

问题


With EF Core I am creating a principal record, but when adding and saving a dependent record it will attempt to create a new duplicate principal.

I've seen various solutions to this, but I'd like to know why this is happening to make a proper fix.

The entity models are in this fashion.

public class Company
{
    public string ID { get; set; }
    public string Name { get; set; }
}

public class Employee
{
    public string ID { get; set; }
    public string Title { get; set; }
    public string Name { get; set; }

    public string CompanyID { get; set; }

    [ForeignKey("CompanyID")]
    public Company Company { get; set; }
}

A DbContext is created to expose with of these as a DbSet.

public class OrganizationContext : DbContext
{
    public DbSet<Company> Companies { get; set; }
    public DbSet<Employee> Employees { get; set; }

    // ...
}

When passing in a full object from a View to add an Employee to a Company via OrganizationContext, it will attempt to create a new Company record as well.

var comp = new Company()
{
    comp.ID = "1",
    comp.Name = "The Daily Planet"
};

var emp = new Employee()
{
    emp.ID = "00123",
    emp.Title = "Supervisor",
    emp.Name = "Clark Kent",
    emp.CompanyID = "1",
    emp.Company = comp
};

_context.Employees.Add(emp);
_context.SaveChanges();

If I set the Company attribute to be unchanged, it still attempts to insert a new Company.

_context.Employees.Add(emp);
_context.Entry(emp.Company).State = EntityState.Unchanged;
_context.SaveChanges();

If I set emp.Company to null, it won't attempt to add a new Company

emp.Company = null;
_context.Employees.Add(emp);

Is there a correct way to setup model relationships or a structure to add an Employee to a Company without needing to manually alter the object graph before saving?


回答1:


It's because you are using Add method, which by definition cascades the Add operation to each reachable entity:

If you create several new related entities, adding one of them to the context will cause the others to be added too.

If you were using entities with auto generated PKs, the correct way would be to use Update method as explained in the Mix of new and existing entities:

With auto-generated keys, Update can again be used for both inserts and updates, even if the graph contains a mix of entities that require inserting and those that require updating

followed by an example and then:

Update will mark any entity in the graph, blog or post, for insertion if it does not have a key value set, while all other entities are marked for update.

Unfortunately your case is different. There is no universal out of the box method for performing the add or update. One solution is to not set the navigation property, but only the FK property (which you luckily have):

//var comp = new Company()
//{
//    comp.ID = "1",
//    comp.Name = "The Daily Planet"
//};

var emp = new Employee()
{
    emp.ID = "00123",
    emp.Title = "Supervisor",
    emp.Name = "Clark Kent",
    emp.CompanyID = "1",
    //emp.Company = comp
};

_context.Employees.Add(emp);
_context.SaveChanges();

Another way which will cost you a db roundtrip is to resolve the related existing entity from the context:

var comp = _context.Companies.Find("1");

var emp = new Employee()
{
    emp.ID = "00123",
    emp.Title = "Supervisor",
    emp.Name = "Clark Kent",
    //emp.CompanyID = "1", // Not needed, but won't hurt if you include it
    emp.Company = comp
};

_context.Employees.Add(emp);
_context.SaveChanges();

The last option is to use TrackGraph and decide individually for each entity.



来源:https://stackoverflow.com/questions/53544256/saving-dependent-record-without-creating-a-duplicate-principal-record

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!