编辑实体时的 EF 4.1 Code-First 和 ASP MVC 3 问题

发布于 2024-10-31 23:57:30 字数 2292 浏览 11 评论 0原文

我使用 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)
        {
            PropertyInfo[] infos = typeof(Book).GetProperties();
            foreach (PropertyInfo info in infos)
            {
                info.SetValue(internalBook, info.GetValue(book, null), null);
            }                
            service.Entry(internalBook).State = EntityState.Modified;                
            service.SaveChanges();

            //context.Entry(book).State = EntityState.Modified;
            //context.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(book);
    }

I coded my entities with and created DbContext. Then I used MVC Scaffolding to create simple CRUD form for one entity. So far so good, it works as advertised.
Now, I decided to replace scaffolding-generated DbContext with simple Service wrapper over DbContext. All it does is delegate to DbContext.

However, now I have the problem on the following line when tried to edit the entity:

service.Entry(Book).State = EntityState.Modified;

“An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key”

I managed to resolve it like this:

PropertyInfo[] infos = typeof(Book).GetProperties();
foreach (PropertyInfo info in infos)
            {
                info.SetValue(internalBook, info.GetValue(book, null), null);
            }

Basically, I get the entity again and copy properties from entity that was handed to me by View. I have also noted that when I obtain the entity, it is proxy, and the one handed to me is not.

What could be the problem?

Here is my service class:

 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);
    }
}

Here is the Edit action Controller code. I have commented the original, scaffolding-generated code:

    [HttpPost]
    public ActionResult Edit(Book book)
    {
        Book internalBook = service.Query.Single(b => b.Id == book.Id);
        if (ModelState.IsValid)
        {
            PropertyInfo[] infos = typeof(Book).GetProperties();
            foreach (PropertyInfo info in infos)
            {
                info.SetValue(internalBook, info.GetValue(book, null), null);
            }                
            service.Entry(internalBook).State = EntityState.Modified;                
            service.SaveChanges();

            //context.Entry(book).State = EntityState.Modified;
            //context.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(book);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小ぇ时光︴ 2024-11-07 23:57:30

实际上你不需要查询这本书,你可以只使用这两行:

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);
}

你可以从这篇文章下载完整的解决方案: http://blog.jorgef.net/2011/04/ef-poco-proxies-in-mvc.html

Actually you don't need to query the Book, you can just use these two lines:

service.Entry(book).State = EntityState.Modified;
service.SaveChanges();

So this is the complete code:

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

        return RedirectToAction("Index");    
    }    

    return View(book);
}

You can download a complete solution from this post: http://blog.jorgef.net/2011/04/ef-poco-proxies-in-mvc.html

葬シ愛 2024-11-07 23:57:30

您无法附加该书,因为您已将其加载到相同的上下文中。一般做法是这样的:

[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);
}

You can't attach the book because you have loaded it in the same context. General approach is this:

[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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文