无法更新外键引用(导航属性)
我知道这似乎是重复的条目,但我红色了与我的问题相关的所有帖子,但找不到解决方案。我被这个问题困扰了大约一周。也许我做了一些设计问题或者我不知道。问题是我无法更新导航属性,我尝试了几个选项,每次我收到不同的错误或重复的错误。好的,这是场景:
我有一个对象“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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
删除
checkRefercies
因为:List
未修改,因此该方法的第一部分将不会执行。Product
无法转换为Category
并附加到DbSet
。它会抛出异常。Category
已在 Addes 状态下附加(这是错误的,因为它将再次插入类别)。再次附加实体将引发异常。只需将
Category
和Product
附加到listRepository
的上下文中,然后再将它们设置到List
中即可。或者更好地完全重写您的代码并在存储库之间共享上下文。
Remove
checkReferencies
because:List
in your example is not modified so the first part of the method will not be executed.Product
cannot be converted toCategory
and attached toDbSet
. 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
andProduct
to context fromlistRepository
before you set them inList
.Or better completely rewrite your code and share context among repostiories.