【问题标题】:Can't update foreign key reference(navigation property)无法更新外键引用(导航属性)
【发布时间】:2011-03-14 12:24:59
【问题描述】:

我知道这似乎是一个重复的条目,但我将所有与我的问题相关的帖子都涂红了,我找不到解决方案。我被这个问题困扰了大约一周。也许我遇到了一些设计问题或者我不知道。问题是我无法更新导航属性,我尝试了几个选项,每次我遇到不同的错误或重复。好的,这是场景:

我有一个对象“列表”
整数 ID
字符串名称
整数发送类型
Category category //这些是导航属性
Product product //这些是导航属性

Category 和 Product 不知道与 List 的关系。我使用由 CTP5 DbContext Generator Template 生成的 POCO 类,并为每个实体使用一个存储库。在每个存储库中都有对 dbcontext 的引用。

这是控制器:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, List list)
    {
        if (!ModelState.IsValid)
            return View(list);

        List originalList = this._listRepository.Get(id);
        TryUpdateModel(originalList, "List", new string[] { "Name", "SendType"});
        //Here's I tried to update manually like this
        if (list.category.id != originalList.category.id)
        {
           Category category = this._categoryRepository.GetNoTracking(list.category.id);
           originalList.Category = category; 
        }
        if (list.product.id != originalList.product.id)
        {
           Product product = this._productRepository.GetNoTracking(list.product.id);
           originalList.Product = product; 
        }
        this._listRepository.Save(); //Here's I call only the SubmitChanges()
        return RedirectToAction("Index");                               
    }

如果我直接尝试,我会收到错误

实体类型“DbEntityEntry”不是当前上下文模型的一部分

因为我修改了实体类别或产品的状态(它们来自另一个上下文)

如果我提交更改,而不修改关联,我会收到错误

'IDCategory' 是参考键,无法更新

等等......任何建议将不胜感激,如果我错了,我也可以修改视图模型。我没有想法!谢谢

更新

    //This is in List Repository
    public override void Save()
    {           
        checkReferencies();
        db.SaveChanges();            
    }

    private void checkReferencies()
    {          
         foreach (var entry in db.ChangeTracker.Entries()
                               .Where(e => e.State == EntityState.Modified || e.State == EntityState.Added))
         {
             if (ObjectContext.GetObjectType(entry.Entity.GetType()).Name.Equals("List"))
             {
                 /*In this case I tried to update my object directly with the object that comes form the form
                 if (entry.CurrentValues.GetValue<int>("IDList").ToString() != "0" )
                 {
                     db.Entry(entry.Entity).State = EntityState.Modified;
                 }    */                 
                 if (((List)entry.Entity).Product != null)
                 {
                     db.Entry(((List)entry.Entity).Product).State = EntityState.Unchanged;
                 }
                 if (((List)entry.Entity).Category != null)
                 {
                     db.Entry(((List)entry.Entity).Category).State = EntityState.Unchanged;
                 }
             }
             else if (ObjectContext.GetObjectType(entry.Entity.GetType()).Name.Equals("Product") 
                   || ObjectContext.GetObjectType(entry.Entity.GetType()).Name.Equals("Category"))
             {
                 //here I attach the entry that I added
                 db.Category.Attach((Category)db.Entry(entry).Entity.Entity);

             }
         }
    }

    //This is in categoryRepository
    public Category GetNoTracking(int id)
    {            
        return db.Category.AsNoTracking().Single(l => l.IDCategory == id);
    }

    //This is in productRepository
    public Product GetNoTracking(int id)
    {            
        return db.Product.AsNoTracking().Single(l => l.IDProduct == id);
    }

    //This is my DbContext
    namespace BusinessManagerEmail.Models
    {
         using System;
         using System.Data.Entity;

         public partial class DBMailMarketingEntities : DbContext
         {
             public DBMailMarketingEntities()
             : base("name=DBMailMarketingEntities")
             {
             }

             public DbSet<Category> Category { get; set; }
             public DbSet<Customer> Customer { get; set; }
             public DbSet<Subscription> Subscription { get; set; }
             public DbSet<List> List { get; set; }
             public DbSet<Product> Product { get; set; }
        }
   }

这就是所涉及的所有代码。谢谢!

【问题讨论】:

  • 为什么不在存储库之间共享上下文?
  • 因为这是我在 MVC 中的第一个项目,我遵循了 NerdDinner 的指导方针。我的下一步是添加一个包含上下文的 UnitOfWork。但是现在我必须按照我发布的那样做:((显然不是我的意愿)!
  • “因为我修改了实体类别或产品的状态”:你在哪里做这个,你修改到什么状态?正如 Ladislav 已经指出的那样,如果您在“_listRepository”和“_listCategory”中有不同的上下文,那么category 不会附加到 _listRepository 的上下文中。还是缺少一些重要的代码片段?
  • 是的,它们来自不同的上下文,但我应该什么时候附上呢?我编辑了我的原始帖子,我会向您展示我尝试过的一些代码。
  • @stuzzo:在我看来,ListFormViewModel 的代码 sn-p 和 HTML/Razor sn-p 与您的问题无关。从您的问题中删除它,然后添加代码 _listRepository_listCategory (尤其是那些 Get 方法)的样子。也许也是您派生的 DbContext 的一部分。我认为这对回答您的问题更有帮助。

标签: c# entity-framework asp.net-mvc-3 repository-pattern entity-framework-ctp5


【解决方案1】:

删除checkReferencies 因为:

  • 您的示例中的List 未修改,因此不会执行该方法的第一部分。
  • Product 无法转换为Category 并附加到DbSet。它会抛出异常。
  • Category 已经附加在 Addes 状态(这是错误的,因为它会再次插入类别)。再次附加实体将引发异常。

只需将CategoryProduct 都附加到listRepository 的上下文中,然后再将它们设置为List

或者更好地完全重写您的代码并在存储库之间共享上下文。

【讨论】:

  • 感谢所有建议!我尝试修改它,我希望能解决它!我很确定我需要你的帮助:P!
  • 你完全正确!我删除了所有代码,并根据您的建议重写了它!谢谢你的帮助!抱歉,如果我发布了糟糕的代码!
猜你喜欢
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多