entity-framework - Entity Framework ,从断开连接的区域更新实体时发生引用完整性约束违规错误

标签 entity-framework entity-framework-5

我有以下型号

public class Order
{
    [Key]
    public virtual string OrderNo {get;set;}
    public virtual IList<OrderItem> Items {get;set;}
}

public class OrderItem
{
    [Key]
    public virtual string ItemNo {get; set;}
    public virtual string ParentItemNo {get;set;}
    public virtual string OrderNo {get;set;}

    public virtual OrderItem ParentItem {get;set;}
    public virtual IList<OrderItem> ChildItems {get;set;}
    public virtual IList<ItemProperty> ItemProperties {get;set;}
    public virtual Order Order {get;set;}
}

public class ItemProperty
{
    [Key]
    public virtual string PropertyNo {get; set;}
    public virtual string ParentPropertyNo {get;set;}
    public virtual string OrderItemNo {get;set;}

    public virtual ItemProperty ParentProperty {get;set;}
    public virtual IList<ItemProperty> ChildProperties {get;set;}
    public virtual OrderItem OrderItem {get;set;}
}

我正在断开连接的区域上运行(服务与 Entity Framework 上下文断开连接)

  1. 我创建订单并保存到数据库

客户:

service.CreateOrder(new Order() { OrderN="fksjdf1" });

服务器:

using(EfDbContext context = new EfDbContext())
{
    context.Orders.Add(order);
    context.SaveChanges();
}
  1. 我需要向之前添加的订单中添加一个或多个 OrderItem

客户:

var order = service.GetOrder("fksjdf1");

var item1 = new OrderItem();
item1.ItemNo="i1";
item1.Order=order;
item1.OrderNo=order.OrderNo;
item1.ItemProperties.Add(new ItemProperty()
    PropertyNo="p1",
    OrderItem = item1
})
order.Items.Add(item1);

var item2 = new OrderItem();
item2.ItemNo="i2";
item2.Order=order;
item2.OrderNo=order.OrderNo;
item2.ItemProperties.Add(new ItemProperty()
    PropertyNo="p2",
    OrderItem = item2
});
item2.ItemProperties.Add(new ItemProperty()
    PropertyNo="p3",
    OrderItem = item2
})
order.Items.Add(item2);
service.UpdateOrder(order);

服务器:

using(EfDbContext context = new EfDbContext())
{
    DbEntityEntry dbEntityEntry = context.Entry(order);
    if (dbEntityEntry.State == EntityState.Detached)
    {
        // ERROR
        context.Set<Order>().Attach(order);
    }

    dbEntityEntry.State = EntityState.Modified;
    context.SaveChanges();
}

错误:发生引用完整性约束违规:定义引用约束的属性值在关系中的主体对象和从属对象之间不一致。

为什么我会看到此错误?为什么我不更新这个实体?

如何在断开连接的区域使用 Entity Framework ?

编辑1:

public Order GetOrder(string orderNo)
{
using (EfDbContext context = new EfDbContext())
            {
                context.Configuration.ProxyCreationEnabled = false;
                var order = context.Orders
                    .Include(o => o.OrderItems
                                      .Select(z => z.ItemProperties
                                                       .Select(y => y.ChildProperties)))
                                                       .Where(o => o.OrderNo == orderNo)
                    .FirstOrDefault();
            }
}

最佳答案

您可能会遇到此错误,因为您没有在 ItemProperty 中设置 OrderItemNo,如下所示:

var item1 = new OrderItem();
item1.ItemNo="i1";
item1.Order=order;
item1.OrderNo=order.OrderNo;
item1.ItemProperties.Add(new ItemProperty {
    PropertyNo="p1",
    OrderItem = item1,
    OrderItemNo = item1.ItemNo // = "i1"
});
order.Items.Add(item1);

// and the same for item2

当订单附加到上下文时,相关的订单商品和商品属性也会附加。 ItemProperty 的导航属性 OrderItem 引用具有您提供的键 ("i1") 的实体,但外键 OrderItemNo 没有这个键值。这就是异常所提示的不一致之处。

编辑

不幸的是,更新数据库中的分离对象图并不容易。将实体的状态设置为已修改只会将该实体标记为已修改,而不标记任何相关实体。

您的 GetOrder 方法使事情变得复杂,因为您急切地向客户端加载已经存在的项目和更多相关内容,然后在客户端添加新的 OrderItem 并将其发送新修改的对象图返回到服务器。在服务器端,您现在遇到的问题是,您必须以与新项目(将它们插入数据库)不同的方式处理已经存在的项目(不要将它们插入数据库)。为此,您需要检测哪些项目是旧的,哪些是新的。如果您不在实体本身中传输某些标志来指示实体是否是新的,则必须再次查询数据库并将从数据库加载的对象图与从客户端发送的分离对象图进行比较。大致的实现方式如下:https://stackoverflow.com/a/5540956/270591 (这仅适用于具有子集合的父集合。如果涉及孙子集合 - 就像在您的模型中一样 - 它会变得更加复杂。)

在我看来,如果您不仅拥有尝试处理对象图中所有可能更改的全局 service.UpdateOrder(order) 方法,而且还拥有一些专门的方法,则可以简化整个过程利用您对图表更改的了解 - 在本例中是一种向现有订单添加新 OrderItem 的专用方法。它可能看起来像这样:

var order = service.GetOrder("fksjdf1");

var newOrderItems = new List<OrderItem>();

var item1 = new OrderItem();
item1.ItemNo="i1";
item1.OrderNo=order.OrderNo; // leave the Order property null
item1.ItemProperties.Add(new ItemProperty { PropertyNo="p1" });
newOrderItems.Add(item1);

// the same for item2
newOrderItems.Add(item2);

service.AddNewOrderItems(newOrderItems);

服务方法是:

public void AddNewOrderItems(List<OrderItem> newOrderItems)
{
    using(EfDbContext context = new EfDbContext())
    {
        foreach (var newOrderItem in newOrderItems)
            context.Set<OrderItem>().Add(newOrderItem);

        context.SaveChanges();
    }
}

关于entity-framework - Entity Framework ,从断开连接的区域更新实体时发生引用完整性约束违规错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12976813/

相关文章:

c# - EF Core 左连接计数

c# - 错误 : No Entity Framework provider found for the ADO. 具有不变名称 'System.Data.SqlClient' 的 NET 提供程序

asp.net-mvc - EF oData - 元素类型不是实体类型

c# - 执行 SaveChanges 时排除未修改的字段

entity-framework - 必须首先将连接字符串传递给 EF 5 DbContext 代码,否则命令异常

c# - Database.ExecuteSqlCommand - 捕获 SQL 异常

c# - EntityType 'DbGeography' 没有定义键

asp.net-mvc-4 - MVC "create view"当模型中存在一对多关系时

mysql - 不安装MySqlConnector是否可以编译?

entity-framework - .NET 4.0 上的 Entity Framework 5 - DatabaseGeneratedOption.Identity 未定义