[英]Many to One relationship in EF Core
我正在努力在 EF Core 中实现多对一关系。 这不是一对多,而是多对一。 我有一个名为 Order 的 object,它可以具有特定的 OrderStatus,例如 BackOrder、Rush、Fulfilled。 其中每一个都有许多与之关联的属性,我需要 Order 才能访问这些属性。 例如,每个都有不同的 DeliveryCharge,每个都有不同的 ManufacturingLine,等等。它就像一个具有附加属性的枚举。
我正在使用断开连接的应用程序,因此所有数据都以 JSON 的形式通过网络发送。
在前端查询数据和查看时,使用标准 FK 进行设置即可。 但是,当我保存时,EF 认为 OrderStatus 是一个新实体,因此它会尝试插入,从而导致键冲突。
我已经在保存期间使用“修复”过程进行处理,该过程在保存订单之前重新查询 OrderStatus 并将“新”OrderStatus object 替换为来自数据库的相同订单状态。
有没有办法在 EF 核心中声明多对一关系
这可能是因为您将某些 JSON 直接反序列化为数据库级实体; 序列化程序正在为您重建一个实体图,您将该图交给 EF 并说“保存这个”。 因为序列化程序创建了一个具有现有属性的新 OrderStatus,并且 EF 认为它是新的,所以它会尝试保存它。 这个问题通常可以通过为前端设置一组不同的模型来避免,通过 JSON 在浏览器和网络服务器之间穿梭,而不是用于后端,通过 EF 在 web 服务器和数据库之间穿梭。 该链中间的 web 服务器中的映射过程提供了一个机会来确保 DB 实体图是 EF 可以处理的。
这并不意味着你不能删除和保存一个数据库实体图,尽管我们确实尽量避免将数据库实体发送到前端,但是如果你要保存一个被删除的数据库实体图,它有责任做一些知道实体是否为新实体的过程的一部分,如果存在,则不向 EF 发送完整的新实体。
让你的实体像这样最简单:
public class OrderStatus{
public int Id {get;set;}
public ICollection<Order> Orders {get;set;}
public int DeliveryCharge....
}
public class Order{
public int Id {get;set;}
public int OrderStatusId {get;set;}
public OrderStatus OrderStatus {get;set;}
public blah LotsOf....
}
然后,如果您知道订单状态 ID 存在并想添加一个使用该现有 ID 的订单:
context.Orders.Add(new Order { OrderStatusId = 2, Other = blah });
context.SaveChanges();
或者使用发送 JSON 的“前端构建它而网络服务器只是想要它”的方法:
{
OrderStatusId: 2,
Other: ...
}
并不是:
{
OrderStatus: { Id: 2, DeliveryCharge: 5, ..}
Other: ...
}
做前者可能就像调整你的 javascript 一样简单,所以它只是在发送序列化的 object 中放置一个 ID,而不是放置整个 object; 当用户从组合中选择“$5 express delivery”时,将OrderStatusId:2
放入请求实体中,而不是OrderStaus:{ Id: 2, Delivery: 5, ..}
在后一种形式中,序列化程序将为您构造另一个实体,让您面临后期处理的问题(很简单,只是有点浪费):
foreach(var o in deserializeddOrders){
o.OrderStatusId = o.OrderStatus.Id;
o.OrderStatus = null;
}
如果您不愿意提供 OrderStatusId 并且已经在 memory 中有一个已知的 OrderStatus(您出于某种原因下载了它),您可以:
context.Orders.Add(new Order { OrderStatus = <existing entity>, Other = blah });
context.SaveChanges();
或后处理 deser'd:
foreach(var o in deserializedOrders){
o.OrderStatus = <existing ent>;
}
如果您没有已知实体,最简单的方法是使用您想采用的任何其他检索方法下载现有实体,并将其作为匹配实体提供:
context.Orders.Add(new Order { OrderStatus = context.OrderStatuses.Find(2), Other = blah });
context.SaveChanges();
或者作为后处理:
foreach(var o in deserializedOrders){
o.OrderStatus = context.OrderStatus.Find(o.OrderStatus.Id); //find will only download from db once; further retrievals use a cached item
}
但是不要使用现有 ID 创建新的状态实体,因为 EF 会尝试插入它:
context.Orders.Add(new Order { OrderStatus = new () { Id = 2 }, Other = blah });
context.SaveChanges();
您还可以采取其他措施来解决此问题,例如摆弄更改跟踪器以使 EF 认为存在一个新实体,但我不是粉丝。如果您只有一个 ID,请将其弹出成对。 ..孩子的 Id 属性是预期的解决方案,因此请确保这就是发生的事情
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.