我需要为某些记录切换数据上下文。所以基本上我有db上下文A和B,我使用A获取记录,然后切换到B,更改记录,并保存它们。
当我为B调用Attach时,我得到了多个数据上下文使用记录的异常,当我为A添加Detach时,我得到异常,那些记录没有附加到A.
那么如何切换数据上下文呢?
db_creator 是db context的创建者。在这里,我获取数据(更正版本):
using (var db = db_creator.Create())
{
var coll = db.Mailing.Where(it => !it.mail_IsSent).ToList(); // (*)
coll.ForEach(it => db.Detach(it));
return coll;
}
(*)错误是由重构这一部分造成的,我创建了额外的数据上下文,然后我试图从另一个中分离记录。
现在我想将数据上下文切换到新的,进行一些计算和修改并保存记录。 coll 是记录的列表:
using (var db = db_creator.Create())
{
coll.ForEach(it => db.Mailing.Attach(it));
...
db.SaveChanges();
}
答案 0 :(得分:1)
我建议您更改设计,一次只能有一个上下文。 (根据您的项目类型,这可能会有所不同。通常在网络应用中,每个http请求都有一个上下文。)
例如,在Web应用程序中,您可以执行以下操作:
protected MyContext Context
{
get
{
var context = HttpContext.Current.Items["MyContext"];
if (context == null)
{
context = new MyContext();
HttpContext.Current.Items.Add("MyContext", context);
}
return context as MyContext;
}
}
并将其丢弃在Application_EndRequest中:
app.EndRequest += (sender, args) =>
{
HttpContext.Current.Items.Remove("MyContext");
}
如果您有多种项目类型,请考虑使用Ioc
但是如果您仍想使用两个上下文,则可以执行以下操作(myEntity
是您要分离/附加的对象):
if (context1.Entry(myEntity).State != EntityState.Detached);
{
((IObjectContextAdapter)context1).ObjectContext.Detach(myEntity);
}
context2.MyEntities.Attach(myEntity);
答案 1 :(得分:1)
我得出的结论是,使用ApplyCurrentValues
代替附加是最好的(即更容易避免问题)。那是因为当你打电话给Attach
时,有几件事我们不知道,但可能会以某种方式通过异常浮出水面。我更喜欢按照我控制的方式做事。
var myMailings = db_creator.Create().Mailing.Where(it => !it.mail_IsSent).ToList();
... // make modifications and retrieve coll a collection of Mailing objects
using (var db = db_creator.Create()) {
... // if you want to further modify the objects in coll you should do this before writing it to the context
foreach (Mailing it in coll) {
if (it.EntityKey != null) db.GetObjectByKey(it.EntityKey); // load entity
else db.Mailing.Single(x => x.YourId == it.YourId); // load the entity when EntityKey is not available, e.g. because it's a POCO
db.Mailing.ApplyCurrentValues(it); // sets the entity state to Modified
}
db.SaveChanges();
}
编辑:
我使用Attach测试了此vs的性能。应该注意的是,对于一个带有整数主键的简单表,一个int,一个float和一个用于更新1000个条目的字符串列:差异是2.6s vs 0.27s,所以这个速度要慢得多。
EDIT2:
提出了类似的问题here。答案警告说,将ApplyCurrentValues与timestamp列结合使用。
我还在使用db.GetObjectByKey(it.EntityKey)
加载实体时比较了性能,并且性能差异要小得多。 ApplyCurrentValues则需要0.44秒。