C# 如何通过替换EF中的实体来更新实体?

C# 如何通过替换EF中的实体来更新实体?,c#,entity-framework,C#,Entity Framework,我有一个类Order,它有一个列表和一个客户。我需要更新订单及其子类。首先,我只附加Order对象 但通过这种方式,EF无法理解项目和客户的变化 然后我尝试将子类的状态更改为EntityState.Modified,但这也不起作用。EF中是否有方法使用db中的现有记录重放父类和子类 如果没有,我如何解决这个问题 var temp = db.Orders.Find(order.Id); temp = order; temp.Items = order.Items; temp.Customer =

我有一个类
Order
,它有一个
列表
和一个
客户
。我需要更新订单及其子类。首先,我只附加
Order
对象 但通过这种方式,EF无法理解
项目
客户
的变化

然后我尝试将子类的状态更改为
EntityState.Modified
,但这也不起作用。EF中是否有方法使用db中的现有记录重放父类和子类

如果没有,我如何解决这个问题

var temp = db.Orders.Find(order.Id);
temp = order;
temp.Items = order.Items;
temp.Customer = order.Customer; 
db.SaveChanges(); 
在更改用户操作的顺序后,我也尝试此操作:

db.Orders.Attach(order) ;
db.SaveChanges();

无需附加订单进行更新。使用方法如下:

Db.Entry(temp).State = EntityState.Modified;
Db.SaveChanges();

在EF6上,没有内置的可靠方式将完整的图形(包括相关项)附加到上下文上(除了
Add()
,但它不会更新,只是添加)。事实上,它应该可以工作(并附加完整的对象图),但在实践中,它不起作用,而且非常不一致,因此最好自己附加每个相关的项

有类似的第三方工具可以帮助完成此任务(检查其扩展方法,
DbContext.UpdateGraph()
),但没有可靠的内置方法


我不确定EF Core是否已经实现了它,但它正在讨论中(有-它是为
Add
提供的,但您会看到在整个讨论中提到的
Update
)。但是它是关闭的,我没有密切关注,但我不想知道是否有相关的问题打开)

我没有尝试对具有子类的实体使用此方法,但您可以尝试设置值

context.Entry(temp).CurrentValues.SetValues(order);
context.SaveChanges();
这假设order是实体Orders的一个实例。注意,这将用order的属性完全覆盖temp记录的每个属性


本博客提供了更多信息(也适用于EF Core):

如果您想用相关/子/嵌套引用和集合替换实体,您可以使用跟踪图,因为EF Core 2.2。所有实体ID都应该由数据库生成

将方法添加到上下文中

public void Replace(tenty-oldEntity,tenty-newEntity),其中tenty:class
{
ChangeTracker.TrackGraph(oldEntity,e=>e.Entry.State=EntityState.Deleted);
ChangeTracker.TrackGraph(newEntity,e=>e.Entry.State=e.Entry.IsKeySet?EntityState.Modified:EntityState.Added);
}
用法

var oldOrder=db.Orders
.AsNoTracking()
.包括(o=>o.Items)
.包括(o=>o.Customer)
.Find(newOrder.Id);
db.替换(旧订单、新订单);
db.SaveChanges();
请注意,应使用AsNoTracking

db.Entry(oldOrder).State=EntityState.Detached;

您是想说您正在更改模型,并且希望它会对数据库产生影响吗?但is对db没有影响。这就是你的意思吗?是的。。。从db中提取一个“Order”记录到对象中,并修改它的子类,但EF不将此更改保存到db中。是否执行
数据库。SaveChanges()
?(用对象替换数据库)是。。。我用我的代码更新了我的问题。你可能没有添加你的对象。Db.Entry(order).State=EntityState.Modified;Db.SaveChanges();Db.Entry(temp.State=EntityState.Modified;我使用了它,但出现了以下异常:“附加“DataAccess.Order”类型的实体失败,因为相同类型的另一个实体已具有相同的主键值”,这是因为您执行了一个Find(),将记录从数据库加载到实体缓存中。然后分配一个新对象并将其附加到上下文,创建一个具有相同键(order.ID)的新条目。当您点击SaveChanges()时,EF正确地抱怨两个具有相同键的条目。这段代码对我有效:
context.Update(temp).CurrentValues.SetValues(order)。虽然它不适用于儿童实体。@Alex Zhukovskiy和Dale C-谢谢你的帖子,效果很好!戴尔-你能更新一下链接吗,它得到了404回复。。。