我有以下实体
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public Sections Sections { get; set; }
}
public class Section
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Sections : List<Section>, ICollection<Section>
{ }
我添加了一个带有项目ID 1但没有任何部分的新项目......
现在我想要修改项目并在其中添加新部分,为此,我正在上下文中检索该项目并将其保存在另一个上下文中。在这里,我必须使用两个单独的上下文,因为不确定用户何时更新对象。在此之前我无法保持上下文对象的开放。
Item fAp;
using (var ctx = new MyContext())
{
fAp = ctx.Items.Include(a => a.Sections).Single(a => a.Id == 1);
}
using (var ctx2 = new MyContext())
{
var nsec = new Section()
{
ID = 1,
Name = "App Sec...1"
};
fAp.Sections.Add(nsec);
ctx2.Entry(fAp).State = EntityState.Modified;
ctx2.SaveChanges();
}
通过执行此操作,新部分未添加到数据库中。然后我在调用ctx2.SaveChanges()。
之前修改了代码并添加了以下行 ctx2.Entry(nsec).State = EntityState.Added;
成功保存了。
现在,我的问题是我的数据层次结构非常复杂,我的意思是Section类也有很多子导航属性,那些属性也有很多,等等。
跟踪所有此类属性并手动设置其状态将非常困难。在这种情况下如何更新数据?
还有一件事,我不会使用急切加载,我的意思是我在检索Item对象时不会使用'Include'。我将在需要时使用显式加载,最后想要更新对象。
有什么最好的建议吗?
答案 0 :(得分:0)
设置状态仅影响您传递给Entry
调用的单个实体。一旦为数据持久性使用新的上下文实例,就必须始终告诉要保存的任何实体的EF状态。
在您的情况下,您需要执行以下任一操作:
ctx2.Items.Attach(fAp); // Now you informed context about existing entity
fAp.Sections.Add(nsec); // Now you told both context and your item that new section exists
或者这个(避免一些其他问题的首选解决方案):
fAp.Sections.Add(nsec); // Your item is not tracked by the new context yet
ctx2.Items.Add(fAp); // Now context things that both item and section are new
ctx2.Entry(fAp).State = EntityState.Unchanged; // Make sure that item is not inserted again
或者这个:
fAp.Sections.Add(nsec); // Your item is not tracked by the new context yet
ctx2.Items.Attach(fAp); // Now context things that both item and section are existing
ctx2.Entry(nsec).State = EntityState.Added; // Make sure that section is tracked as new
跟踪所有这些属性和设置将非常困难 他们手动的状态。在这种情况下如何更新数据?
您的代码正在进行这些更改,因此它不应该那么困难。您甚至可以向每个实体添加一些其他属性,如IsDirty
,并将其用作帮助程序来跟踪实体的状态。
答案 1 :(得分:0)
更新实体
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public Sections Sections { get; set; }
public OtherInfo Info { get; set; }
}
public class OtherInfo
{
public Guid Id {get;set;}
public string Description {get;set;}
}
在检索Item的对象后,用户可以修改任何内容。举个例子,用户只是插入一个新的Section,并通过传递对象Item来调用commit方法。
存储库类中的Commit方法
public void Commit(Item fAp)
{
using (var ct = new MyContext())
{
bool isExist = ct.Item.Any(a => a.Id == fAp.Id);
if (!isExist)
{
ct.Items.Add(fAp);
}
else
{
ct.Items.Attach(fAp);
ct.Entry(fAp).State = EntityState.Modified;
}
ct.SaveChanges();
}
}
在commit方法中,我不知道用户对该对象做了什么。在我的测试中,我添加了部分并调用此方法。由于,OtherInfo未被修改,因此抛出错误称为OtherInfo表的重复主键。
所以,为了使它工作,我必须改变所有实体的状态,如
部分 - 已添加; OtherInfo - NoChange;项目 - NoChange
由于结构有点复杂,因此很难跟踪所有实体。
这种方法(提交方法)是正确还是建议更好的解决方案?