2011-04-17 144 views
2

我在保存对数据库的更改时遇到问题。SaveChanges()实体框架问题4.1

我更新了模型中的在我的控制器,但是当我保存的SaveChanges使用()我最终在数据库B.

重复的项目

中的UpdateModel(后)的变化被称为我检查了Bs属性,这是因为我期望但是在SaveChanges()被调用后,如果我检查Bs属性,我会看到Id完全不同(新的Id和新条目)。

我的班级与此类似:

public class A 
{ 
    [HiddenInput(DisplayValue = false)] 
    public int AId { get; set; } 

    public string Name { get; set; } 

    public virtual ICollection<B> Bs{ get; set; } 
} 

public class B 
{ 
    [HiddenInput(DisplayValue = false)] 
    public int BId { get; set; } 

    public string Name { get; set; } 

    public virtual ICollection<A> As{ get; set; } 
} 

我的控制器是这样的:

[HttpPost] 
    public ActionResult Edit(A theA) 
    { 
     try 
     { 
      db.Entry(theA).State = EntityState.Modified; 

      foreach (var item in theA.Bs) 
      { 
       db.Entry(item).State = EntityState.Modified; 
      } 

      db.SaveChanges(); 

      return RedirectToAction("Index"); 
     } 
     catch 
     { 
      return View(); 
     } 
    } 

难道我做错了什么?

在此先感谢

+0

您的控制器方法对于查看从DB中检索对象的位置很重要,可以修改它们并调用SaveChanges。 – Slauma 2011-04-17 12:53:40

回答

7

这是常见的行为。问题在于EF不知道您附加了现有B,因此它会自动插入新记录。你必须通过调用说,B是现有的EF:

// here add B to the collection in the A and after that call: 
dbContext.Entry<B>(someB).State = EntityState.Unchanged(); 

或通过连接B你它A加至收集之前(我不知道,如果在ASP.NET MVC使用UpdateModel时,这是可能的)。

dbContext.Bs.Attach(someB); 
// now add B to the collection in the A 

另一种可能是先装入数据库BA添加加载对象的集合,但它是额外的往返到数据库。

int id = someB.Id; 
var loadedB = dbCotnext.Bs.Single(b => b.Id == id); 
someA.Bs.Add(loadedB); 
dbContext.As.Add(someA); 
dbContext.SaveChanges(); 

结论:每次你打电话Add如插入,除非你先(将它们添加到插入的父母前 - 第二和第三个例子)附加相关实体的整个对象图被跟踪时,或者除非你手动更改状态的相关实体在添加父代后回到未改变。 (第一个例子)。

+0

谢谢, 我尝试了第一种方法,但是一旦它被调用,我就会收到以下消息: “AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象发生冲突,请确保键值是唯一的调用AcceptChanges“。 – Raha 2011-04-17 14:50:13

+0

那么你是如何得到你的B实例的?你是如何创建你的上下文的?上下文是否按每个请求实例化,并且B是否只有每个上下文仅使用一次(单个实例)的给定密钥? – 2011-04-17 14:54:54

+0

我已将ActionMethod添加到问题中,请问您可以看一下吗? – Raha 2011-04-17 17:23:48