Entity framework EF 4.1编辑实体时代码优先和ASP MVC 3问题

Entity framework EF 4.1编辑实体时代码优先和ASP MVC 3问题,entity-framework,asp.net-mvc-3,poco,ef-code-first,scaffolding,Entity Framework,Asp.net Mvc 3,Poco,Ef Code First,Scaffolding,我用DbContext对实体进行编码并创建了DbContext。然后我使用MVC脚手架为一个实体创建简单的CRUD表单。到目前为止,一切都很好,正如广告所宣传的那样。 现在,我决定用DbContext上的简单服务包装器替换脚手架生成的DbContext。它所做的只是委托给DbContext 但是,现在我在尝试编辑实体时,在以下行出现了问题: service.Entry(Book).State = EntityState.Modified; “ObjectStateManager中已存在具有相同

我用DbContext对实体进行编码并创建了DbContext。然后我使用MVC脚手架为一个实体创建简单的CRUD表单。到目前为止,一切都很好,正如广告所宣传的那样。 现在,我决定用DbContext上的简单服务包装器替换脚手架生成的DbContext。它所做的只是委托给DbContext

但是,现在我在尝试编辑实体时,在以下行出现了问题:

service.Entry(Book).State = EntityState.Modified;
“ObjectStateManager中已存在具有相同键的对象。ObjectStateManager无法跟踪具有相同键的多个对象”

我设法这样解决了这个问题:

PropertyInfo[] infos = typeof(Book).GetProperties();
foreach (PropertyInfo info in infos)
            {
                info.SetValue(internalBook, info.GetValue(book, null), null);
            }
基本上,我再次获取实体,并从视图交给我的实体复制属性。我还注意到,当我获得实体时,它是代理,而交给我的那一只不是

有什么问题吗

这是我的服务课:

 public class BookService
{

    private DbContext context;
    private DbSet<Book> set;    

    public BookService(DbContext context, DbSet<Book> set) {
        this.context = context;
        this.set = set;
    }

    public IQueryable<Book> Query
    {
        get { return set; }
    }

    public virtual void Add(Book entity)
    {
        set.Add(entity);
    }        

    public virtual void Remove(Book entity)
    {
        set.Remove(entity); 
    }

    public virtual void SaveChanges() {
        context.SaveChanges();
    }

    public List<Book> All() {
        List<Book> books = set.ToList();
        return books;
    }

    public DbEntityEntry<Book> Entry(Book book) {
        return context.Entry(book);
    }
}

无法附加该书,因为已在同一上下文中加载该书。一般做法是:

[HttpPost]
public ActionResult Edit(Book book)
{
    Book internalBook = service.Query.Single(b => b.Id == book.Id);
    if (ModelState.IsValid)
    {             
        service.Entry(internalBook).CurrentValues.SetValues(book);                
        service.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(book);
}

实际上,您不需要查询书籍,只需使用以下两行:

service.Entry(book).State = EntityState.Modified;
service.SaveChanges();
这是完整的代码:

[HttpPost]
public ActionResult Edit(Book book)
{    
    if (ModelState.IsValid)    
    {                     
        service.Entry(book).State = EntityState.Modified;
        service.SaveChanges();        

        return RedirectToAction("Index");    
    }    

    return View(book);
}

您可以从这篇文章下载完整的解决方案:

service.Entry(Book.State=EntityState.Modified)前面的代码是什么?我已将问题编辑为包含您要求的代码。当您删除该行时会发生什么?它不保存更改吗?我原以为上下文可以跟踪更改,而无需手动更改EntityState。@Carlino,确切地说,id不保存更改。正如我所提到的,代码是由Mvc Scaffolding,works生成的,我试图以尽可能少的方式修改它。我注意到的一件事是,在我的fix internalBook中,它实际上是一个代理,而我作为参数接收的book则不是。这与我所做的类似。。。但我猜,搭建好的代码会用每个请求初始化新的上下文吗?如下所示:private BooksAndAuthorsWebContext context=new BooksAndAuthorsWebContext();这意味着每个请求都会实例化新控制器。必须使用每个请求初始化上下文。如果您没有为每个请求创建新的上下文,您将遇到严重的问题:我正在使用Ninject。如果我理解正确,InRequestScope应该可以做到这一点
[HttpPost]
public ActionResult Edit(Book book)
{    
    if (ModelState.IsValid)    
    {                     
        service.Entry(book).State = EntityState.Modified;
        service.SaveChanges();        

        return RedirectToAction("Index");    
    }    

    return View(book);
}