Entity framework 实体框架SaveChanges()在不同的DbContext中插入不必要的行

Entity framework 实体框架SaveChanges()在不同的DbContext中插入不必要的行,entity-framework,entity,savechanges,Entity Framework,Entity,Savechanges,我的超市模型包含一个StockItem类和一个Alert类,该类包含一个StockItem字段: 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

我的超市模型包含一个StockItem类和一个Alert类,该类包含一个StockItem字段:

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; }
}
我有一个函数,它使用一个DbContext获取所有StockItems:

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();
        }
     }
}
以及处理这些项目并在另一个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();
        }
     }
}
foreach(项目中的变量项目)
{
if(item.CurrentQuantity
问题是:保存警报时,会将一个新的库存项目(具有不同的id)添加到数据库中,尽管它已经存在!
有什么解决办法吗?

我想你应该先附上库存商品。 试试这个:

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();
        }
     }
}
foreach(项目中的变量项目)
{
if(item.CurrentQuantity
您正在处理MyDbContext,因此EF将所有库存项作为独立项(分离项)进行处理,当您将它们添加到不同的上下文中时,context假定它是一个新项,并将插入该项

最好的方法是在您想要进行的更改中保持上下文的活跃性。还要注意的是,将上下文保持活动状态更长时间并不意味着您将一直保持数据库连接打开。只有在执行查询并调用保存更改时,EF才会自动打开和关闭数据库连接


否则你必须按照本的建议附上。

我明白了。但是现在我必须在db.SaveChanges()的许多情况下执行附加。实体框架不能根据StockItem的ID自动知道它已经在数据库中吗?如果您创建一个新的上下文,ef不查询数据库就无法知道它。。。因此,如果您不想重新连接,您应该更改上下文生命周期(而不是在每次操作后进行处置并缓存上下文)@Sean:No EF不会为您执行任何类似的操作。您有责任告知EF什么是新的、更新的、删除的或未更改的。通过在警报上调用
Add
,您将附加警报对象图中的所有实体,并将它们标记为已插入。我按照建议这样做,并保留了一个静态DbContext实例,在获取方法中使用它,随后在创建警报的方法中使用它。这一切都非常有效,但当我使用WCF调用这些方法时,重复再次出现。在debug中,它们似乎仍然使用相同的DbContext。我还尝试将WCF配置为在PerSession中工作,但也没有起到任何作用。我按照您的建议做了,保留了一个静态DbContext实例,并在获取方法中使用它,后来在创建警报的方法中使用它。这一切都非常有效,但当我使用WCF调用这些方法时,重复再次出现。在debug中,它们似乎仍然使用相同的DbContext。还尝试将WCF配置为在会话中工作,但也没有帮助。在WCF中,您的静态实例将无法工作,您应该使用HttpContext.Current.Session来存储DbContext,这将存储会话的上下文,但有一个问题,您应该在会话保持打开的位置进行某种ping。否则,您可以尝试切换到RIA服务,它做得非常好。