【问题标题】:CTP5 update cascadeCTP5 更新级联
【发布时间】:2011-02-18 08:17:42
【问题描述】:

我需要 CTP5 的添加或更新模式。 假设模型:

public class User
{
    public int UserId { get; set; }
    public ICollection<Address> Addresses { get; set; }
}
public class Address
{
    public int AddressID { get; set; }
    public string Location { get; set; }
}

如果我添加一个新用户,相应的地址表也会被填充。 但是如果用户已经在数据库中,我会得到一个 DbUpdateException。在这种情况下,我希望使用新数据更新数据库中的数据。我该怎么做?

数据库中的数据

表地址

地址ID位置

1 约翰广场

2 玛丽广场

3 吉米广场

我更新的用户在地址集合 1 中具有 AddressId:2, Location=GeorgePlace。 但是对于 ID=2,在 Db 中已经有一条 location=MarryPlace 的记录。我希望 GeorgePlace 覆盖 MarryPlace。

我不能拥有未分配给用户的地址

我创建了一个类似的用户:

var user=new User();
user.Id=GetUserIDfromService();
foreach(var address in GetAddressesFromService(user.Id)){
    user.Addresses.Add(address);
}
context.Users.Add(user);
context.SaveChanges();//this may throw an exception, because there is already a user with this id.

【问题讨论】:

  • @Ryan:所以您可以在数据库中拥有未分配给任何用户的地址?您也可以发布您的更新代码吗?
  • 我会做 Jakub Konecki 建议的事情。但我希望能够做一些类似 context.Users.Add(newUser); context.SaveChanges()
  • @Ryan:发布您的代码。我们需要知道您是如何接收/创建您想要更新的用户和地址对象以及您的实际更新方法。
  • @Ryan:GetAddressFromService 在做什么?是否从其他上下文实例的数据库中加载地址?
  • 不,它从网络服务获取数据

标签: c# entity-framework entity-framework-ctp5


【解决方案1】:

如果您想更新现有用户,请不要插入(不要调用Add()) 首先按 Id 加载用户,然后修改其属性并在上下文中调用 SaveChanges()

var db = new DatabaseContext();
var user = db.Users.Find(myUserId);
user.Name = "New Name";
db.SaveChanges();

【讨论】:

  • 是的,但这需要我对每个地址执行相同的操作,而不是对用户执行相同操作。有些地址是新的,所以我需要添加它们,有些需要更新
【解决方案2】:

您当前的问题是您准备新的 User 对象并填充其地址,但地址不是通过相同的上下文从 DB 加载的,因此上下文不知道它们。当您调用 Add 方法时,它将获取对象图中的所有对象并将它们标记为新的(要插入的)。避免这种情况的唯一方法是手动说出哪个地址是新的,哪个只是在将地址添加到用户实例之前从上下文中修改或加载地址。

标记地址的代码如下:

var user = new User(); 
user.Id = GetUserIDfromService(); 
context.Users.Add(user); 
foreach(var address in GetAddressesFromService(user.Id))
{
  context.Addresses.Attach(address);
  // Let say that new address always have 0 Id      
  context.Entry(address).State = address.Id == 0 ? EntityState.Added : EntityState.Modified;      
  user.Addresses.Add(address); 
} 

context.SaveChanges();

【讨论】:

  • 我可能已经有一个带有我要添加的 ID 的地址。不幸的是,我不能假设新地址为 0。我的解决方案是尝试将用户添加为新地址,而不是在 DbUpdateException 发生时捕获它,然后在 catch 块中将其添加为已修改。你怎么看?
  • @Ryan:这看起来与此类似:stackoverflow.com/questions/5024094/… 我个人反对这些解决方案,因为如果您使用不知情的实体,如果它们是新的或修改过的,那么您的应用程序中就会发生奇怪的事情.它通常可以工作,但它会一一处理故障,所以我希望对于应该修改的 20 个地址,您必须捕获异常 20 次。
  • 你如何建议我应该以其他方式实现这个?
  • @Ryan:如果你不知道地址是否是新的,你应该先尝试加载它。
  • 我坚持这样做,但我认为异常处理会更容易。如果我第一次尝试加载,比添加每个地址都有 2 个 Db 操作。如果我使用异常,如果数据是新的,我有 1Db op,如果地址已经在,我有 2DbOp+1exception。感谢您的回复。您认为我使用异常处理做出了正确的决定,还是应该先加载数据?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
相关资源
最近更新 更多