EF5代码首先使用ASP.NET Web API:更新具有多对多关系的实体

wsed 发布于 2019-03-15 最后更新 2019-03-15 14:08 1 浏览

我正在尝试使用ASP.NET Web API和实体框架5代码首先在我的数据库中更新Customer,但它不起作用。我的实体看起来像这样:

public class CustomerModel
{
    public int Id { get; set; }
    public string Name { get; set; }
// More fields
public ICollection<CustomerTypeModel> CustomerTypes { get; set; }
}
public class CustomerTypeModel
{
    public int Id { get; set; }
    public string Type { get; set; }
[JsonIgnore]
    public ICollection<CustomerModel> Customers { get; set; }
}
没有什么特别的。我已经构建了一个Web界面,用户可以通过提供名称和检查一个或多个客户类型来添加客户。当点击提交按钮时,数据被发送到我的Web API方法:
public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        context.Customers.Attach(customer);
        context.Entry(customer).State = EntityState.Modified;
        context.SaveChanges();
    }
}
这会更新客户字段,但相关的客户类型将被忽略。传入的customer对象确实包含它应该关联的CustomerTypes列表:
[0] => { Id: 1, Type: "Finance", Customers: Null },
[1] => { Id: 2, Type: "Insurance", Customers: Null }
[2] => { Id: 3, Type: "Electronics", Customers: Null }
但是,EF并没有考虑这个列表并添加/删除关联的实体,而是忽略它。即使删除了新的关联,现有的关联也会被忽略。 在将客户插入数据库时​​,我遇到了类似的问题,当我将这些实体的状态调整为EntityState.Unchanged时,这个问题就解决了。当然,我试图在我的更新场景中应用这个相同的魔术修复:
public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        foreach (var customertype in customer.CustomerTypes)
        {
            context.Entry(customertype).State = EntityState.Unchanged;
        }
context.Customers.Attach(customer);
        context.Entry(customer).State = EntityState.Modified;
        context.SaveChanges();
    }
}
但EF始终显示相同的行为。 有想法该怎么解决这个吗?或者我应该只是对CustomerTypes清单做一个手动清除,然后手动添加它们? 提前致谢。 J.P
已邀请:

dut

赞同来自:

更清洁的解决方案是:

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        var customerInDb = context.Customers.Include(c => c.CustomerTypes)
            .Single(c => c.Id == customer.Id);
// Updates the Name property
        context.Entry(customerInDb).CurrentValues.SetValues(customer);
// Remove types
        customer.CustomerTypes.Clear();
// Add new types
        foreach (var type in customer.CustomerTypes) 
        {
            context.CustomerTypes.Attach(type);
            customerInDb.CustomerTypes.Add(type);
        }
context.SaveChanges();
    }
}

dodit

赞同来自:

仅通过设置实体状态,这无法解决。您必须首先从数据库加载客户,包括其所有当前类型,然后根据已发布客户的更新类型集合从已加载客户中删除类型或添加类型。更改跟踪将完成剩余工作以从连接表中删除条目或插入新条目:

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        var customerInDb = context.Customers.Include(c => c.CustomerTypes)
            .Single(c => c.Id == customer.Id);
// Updates the Name property
        context.Entry(customerInDb).CurrentValues.SetValues(customer);
// Remove types
        foreach (var typeInDb in customerInDb.CustomerTypes.ToList())
            if (!customer.CustomerTypes.Any(t => t.Id == typeInDb.Id))
                customerInDb.CustomerTypes.Remove(typeInDb);
// Add new types
        foreach (var type in customer.CustomerTypes)
            if (!customerInDb.CustomerTypes.Any(t => t.Id == type.Id))
            {
                context.CustomerTypes.Attach(type);
                customerInDb.CustomerTypes.Add(type);
            }
context.SaveChanges();
    }
}