我可能完全错了,但使用EF4进行简单的插入和更新让我感到疯狂。(EF新手)
我创建了一个点头项目并上传到这里
如果您愿意,可以随意下载并解决问题。这会非常棒。
简而言之,我希望有人告诉我,我怀疑的并非如此。
假设您有一个客户对象。你是否需要在更新之前先获取它,就像删除一样?这对我来说似乎很疯狂。
鉴于您有一个保存方法(插入和更新都在这里完成),您将客户传递给它。您已经拥有所有详细信息。您如何修改以使其工作?我得到各种各样的错误。 每当我需要修改客户的孩子时,我是否需要访问数据库?
public void Save(CustomerDTO customerDTO)
{
//convert dto to EF entity
var entityCustomer=ToEntityCustomer(customerDTO)
using(ctx=new CustomerContext())
{
if(efCustomer.CustomerId > 0)
{
//UPDATE
//DO I NEED TO FETCH MY CUSTOMER AGAIN FROM THE DB EVEN THOUGH I ALREADY HAVE
//HAVE ALL THE DETAILS? I have not done it here.?????
ctx.Customers.Attach(entityCustomer);
ctx.ApplyCurrentValues(entityCustomer);
//Also Customer has addresses so
foreach(var address in entityCustomer.Addresses)
{
//some may be new addresses some might be modified one
?????? lost
}
}
else
{
///INSERT
ctx.Customers.AddObject(entityCustomer);
ctx.ObjectStateManager.ChangeObjectState(entityCustomer,EntityState.Added);
foreach(var address in entityCustomer.Addresses)
{
ctx.ObjectStateManager.ChangeObjectState(address ,EntityState.Added);
}
}
ctx.SaveChanges();
}
}
答案 0 :(得分:4)
如果您不想在保存之前获取对象,这是一种方法:
public bool Save(CustomerInfo customerInfo)
{
var entityCustomer = ToEntityCustomer(customerInfo);
using (var ctx = new CustomerContext())
{
ctx.ContextOptions.LazyLoadingEnabled = false;
DataAccess.Address[] addresses = new DataAccess.Address[entityCustomer.Addresses.Count];
entityCustomer.Addresses.CopyTo(addresses, 0);
entityCustomer.Addresses.Clear();
if (customerInfo.Id == 0) {
ctx.Customers.AddObject(entityCustomer);
}
else if (customerInfo.Id > 0) {
ctx.Customers.Attach(entityCustomer);
ctx.ObjectStateManager.ChangeObjectState(entityCustomer, EntityState.Modified);
}
foreach (var address in addresses) {
if (address.AddressID == 0) {
ctx.Addresses.AddObject(address);
entityCustomer.Addresses.Add(address);
}
else if (address.AddressID > 0) {
ctx.Addresses.Attach(address);
ctx.ObjectStateManager.ChangeObjectState(address, EntityState.Modified);
if (customerInfo.Id == 0) {
// New Customer so we need to add the existing addresses
// since the FK on Address is 0
entityCustomer.Addresses.Add(address);
}
}
}
ctx.SaveChanges();
return true;
}
}
诀窍是在父(例如Customer)上执行Attach / AddObject之前删除子节点(例如地址),因为这两个操作将影响整个图形,这将导致各种问题。
答案 1 :(得分:3)
您不必在更新前加载对象 - 请检查this answer。但是如果你想使用相关的对象,它真的很有用。在您的情况下,Address实体可能与一对多关系中的Customer enity相关。如果要在不加载实体图的情况下使用地址修改客户,则必须知道修改,插入和删除了哪些地址。对于一对多关系,通常可以通过这些规则进行模拟:
你可以看到这种技术不是很好,因为你总是更新未更改的实体,你必须以不同的方式处理删除,然后只从Customer实体中的Addresses集合中删除它们。此技术也适用于没有父实体的相关enity不存在的聚合。如果你只能删除关系,但实体仍然在数据库中,这种技术是无用的,你需要找到另一种更改跟踪机制 - 如果你想跟踪多对多关系中的变化,这正是如此。这就是我放弃这种技术的原因,以及为什么我在处理更改之前从数据库加载修改后的entites。关于这个问题还有另一个post。
如果您不想自己跟踪状态,可以查看Self tracking entities(STE),但要注意他们的drawbacks。
顺便说一下。删除操作也可以在不首先加载实体的情况下执行。您通常可以创建虚拟实体(空)并仅设置其Id和并发处理程序(我总是使用时间戳)。然后,您可以将此实体附加到上下文并将其删除。但是,如果实体与其他权利处于子女关系,这将不起作用。在这种情况下,您还必须手动删除关系或将抛出异常。如果首先从数据库加载实体,则不会发生这种情况。