2011-05-24 53 views
4

我的超市模式包含StockItem类和含有StockItem领域的Alert类:实体框架的SaveChanges()在不同的DbContext插入不必要的行

public class StockItem 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public int CurrentQuantity { get; set; } 
    public int MinQuantity { get; set; } 
} 

public class Alert 
{ 
    public int ID { get; set; } 
    public int Message{ get; set; } 
    public virtual StockItem StockItem { get; set; } 
} 

我有一个获取所有StockItems一个的DbContext功能:在一个又一个的DbContext

using (var db = new MyDbContext()) 
{ 
    return db.StockItems.ToList(); 
} 

以及处理这些物品的另一个功能,并增加新的警报:

foreach (var item in items) 
{ 
    if (item.CurrentQuantity < item.MinQuantity) 
    { 
     using (var db = new MyDbContext()) 
     { 
      db.Alerts.Add(new Alert(){StockItem = item, Message = "Low Quantity"}); 
      db.SaveChanges(); 
     } 
    } 
} 

问题是:当保存警报时,一个新的股票项目(具有不同的ID)被添加到数据库,虽然它已经在那里! 任何解决方案?

回答

5

我想你应该Attach第一次的stockitem。 试试这个:

foreach (var item in items) 
{ 
    if (item.CurrentQuantity < item.MinQuantity) 
    { 
     using (var db = new MyDbContext()) 
     { 
      db.StockItems.Attach(item); 
      db.Alerts.Add(new Alert {StockItem = item, Message = "Low Quantity"}); 
      db.SaveChanges(); 
     } 
    } 
} 
+0

我明白了。但现在我必须在db.SaveChanges()的许多情况下执行附加操作。根据StockItem的ID,Can not Entity Framework会自动知道它已经在数据库中了吗? – Sean 2011-05-24 08:24:10

+0

如果你创建一个新的上下文,那么在不查询数据库的情况下ef无法知道它......所以,如果你不想重新连接,你应该改变上下文生命周期(不要在每次操作之后处理并缓存上下文) – benwasd 2011-05-24 08:31:02

+1

@肖恩:没有EF不会为你做这样的事情。您有责任告知EF什么是新的,已更新,已删除或未更改。通过在警报上调用“添加”,您可以将所有实体附加到Alert的对象图中,并将它们标记为插入。 – 2011-05-24 09:21:58

0
using (var db = new MyDbContext()) 
{ 
    var items = db.StockItems.ToList(); 
    foreach (var item in items) 
    { 
     if (item.CurrentQuantity < item.MinQuantity) 
     { 
     db.Alerts.Add(new Alert {StockItem = item, 
      Message = "Low Quantity"}); 
     db.SaveChanges(); 
     } 
    }   
} 

在这种情况下,你不需要做连接。 EF只能跟踪在其自己的生命周期的变化,当你做你的第一种情况下,

using (var db = new MyDbContext()) 
{ 
    return db.StockItems.ToList(); 
} 

你要丢弃MyDbContext,所以EF使所有库存物品作为独立(独立项目),当你将它们添加到不同的上下文,上下文假定它是一个新项目,它会插入一个新项目。

最好的方法是保持上下文贯穿你想要做的改变。另外请注意,保持上下文活动时间更长并不意味着您将始终保持数据库连接处于打开状态。只有当您执行查询并且您正在调用保存更改时,EF才会自动打开和关闭数据库连接。

否则,你必须附上本建议。

+0

我照你的建议做了,并且保存了一个静态的DbContext实例,并在提取方法中使用它,后来在创建警报的方法中使用它。这一切都很好,但是当我使用WCF调用这些方法时,重复到达了。在调试中,它似乎仍然使用相同的DbContext。也尝试配置WCF工作PerSession,并没有帮助。 – Sean 2011-05-24 10:36:09

+0

在WCF中,你的静态实例将不起作用,你应该使用HttpContext.Current.Session来存储你的DbContext,这将存储你的会话上下文,但是有一个问题,你应该有一些ping会话的地方继续开放。否则,你可以尝试切换到RIA服务,它做得很好。 – 2011-05-24 13:42:10

相关问题