将更改保存在数据库中时,将返回以下消息的异常:
实体类型'Order.CustomerDeliveryDetails#CustomerDetails'的属性'OrderId'是键的一部分,因此无法进行修改或将其标记为已修改。要使用标识的外键更改现有实体的委托人,请先删除依赖项,然后调用“ SaveChanges”,然后将依赖项与新委托人相关联。
使用“代码优先”方法以实体框架核心实现数据库。 Order.CustomerDeliveryDetails
是实体CustomerDetails
的拥有类型(Order
类型)。 CustomerDetails
没有名为OrderId
的属性。据我了解,OrderId
是implicit key,由实体框架核心生成为shadow property。
这些类的结构如下:
public class Order
{
public int Id { get; set; }
public CustomerDetails CustomerDeliveryDetails { get; set; }
}
[Owned]
public class CustomerDetails
{
public string Street { get; set; }
}
对象更新如下:
var order = await orderContext.Orders
.Where(o => o.Id== updateOrder.Id)
.FirstOrDefaultAsync();
order.CustomerDeliveryDetails.Street = updateOrder.CustomerDeliveryDetails.Street;
await orderContext.SaveChangesAsync();
我无法理解的是在无法直接在代码中直接访问OrderId
的情况下。
我唯一想到的可能是导致此错误的原因是,此更新是在Azure的定时Web作业上运行的。更新通过相关单元测试的事实支持了这种预感。可能与race condition有关吗?
更新:
我相当确定该错误来自某种竞争状况。定时的webjob加载需要每2分钟更新一次的订单列表。只要列表包含的订单少于+ -100,更新就可以正常进行,但是一旦列表变得更长,更新就会开始失败。
如果列表过长,webjob可能无法在2分钟内完成所有订单的更新。
通过依赖项注入来添加上下文,如下所示:
serviceProvider.AddDbContext<OrdersContext>(options => options.UseSqlServer(ctx.Configuration["ConnectionString"], sqlOptions => sqlOptions.EnableRetryOnFailure()));
我最好的想法是,上下文在Webjob的多个调用之间共享,这会导致错误。
答案 0 :(得分:0)
这归结为您与数据库的关系。您使用数据库优先还是代码优先的方法?如何定义模型? Order,CustomerDetails和CustomerDeliveryDetails表之间的关系是什么? 请提供代码,我们将为您提供解决方案。