无法更新外键引用(导航属性)

发布于 2024-10-22 03:23:53 字数 4333 浏览 2 评论 0原文

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

我有一个对象“List”
整数 ID
字符串名称
int 发送类型
Category类别 //这些是导航属性
产品产品//这些是导航属性

Category 和 Product 不知道与 List 的关系。我使用由 CTP5 DbContext 生成器模板生成的 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; }
        }
   }

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

I know that it seems a duplicate entry, but I red all the posts related with my problem and I can't find the solution. I'm stuck with this problem about one week. Maybe I have made some design problem or I don't know. The problem is I can't update a navigation property, I tried several options, everytime i got a different error or a duplicate. Ok, here's the scenario:

I have an object "List"
int ID
string Name
int SendType
Category category //these are navigation property
Product product //these are navigation property

Category and Product don't know about the relation with List. I use POCO classes generated by the CTP5 DbContext Generator Template and I use a repository for every entity. In each repository there's a reference to the dbcontext.

And this is the controller:

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

If I try directly I receive the error

The entity type 'DbEntityEntry' is not part of the model for the current context

because I modify the state of the entity Category or product(they are from another context)

If I submit the changes, without modifying the association, I receive the error

'IDCategory' is a reference key and cannot be updated

And so on......Any suggest will be appreciated, I can also modify the viewmodel if I'm wrong.I'm without ideas! Thanks

UPDATE

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

This is all the code involved. Thanks!

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

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

发布评论

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

评论(1

街角卖回忆 2024-10-29 03:23:53

删除 checkRefercies 因为:

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

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

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

Remove checkReferencies because:

  • List in your example is not modified so the first part of the method will not be executed.
  • The Product cannot be converted to Category and attached to DbSet. It will throw exception.
  • Category is already attached in Addes state (which is wrong because it will insert category again). Attaching entity again will throw the exception.

Just attach both Category and Product to context from listRepository before you set them in List.

Or better completely rewrite your code and share context among repostiories.

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