【发布时间】:2019-11-18 08:45:26
【问题描述】:
所以我最近采用了一个我们拥有的系统(MVC/实体框架),并添加了一堆缓存存储库来加速它。它在测试中似乎工作正常,但是当我们推出它时,我们随机从随机用户那里得到这个错误:
Exception Message: The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
Stack Trace: at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.ValidateContextsAreCompatible(RelatedEnd targetRelatedEnd) at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges) at System.Data.Entity.Core.Objects.ObjectStateManager.PerformAdd(IEntityWrapper wrappedOwner, RelatedEnd relatedEnd, IEntityWrapper entityToAdd, Boolean isForeignKeyChange) at System.Data.Entity.Core.Objects.ObjectStateManager.PerformAdd(IList`1 entries) at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChanges() at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force) at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate) at System.Data.Entity.Infrastructure.DbChangeTracker.Entries() at System.Data.Entity.DbContext.GetValidationErrors() at System.Data.Entity.Internal.InternalContext.SaveChanges() at ClinicalCMS.Domain.CMSContext.SaveChanges() in C:\Projects\BeaconEDC\ClinicalCMS.Domain\CMSContext.cs:line 255 at BeaconEDC.Areas.DataEntry.Controllers.EngineController.MarkComplete(Int64 studyId, Int64 subjectId, Int64 formIteration, StudyAssignment assignment, String caseId, StudyForm studyForm) in C:\Projects\BeaconEDC\BeaconEDC\Areas\DataEntry\Controllers\EngineController.cs:line 375 at BeaconEDC.Areas.DataEntry.Controllers.EngineController.Edit(Int64 studyId, Int64 subjectId, Int64 formIteration, Int64 studyFormId, FormCollection collection) in C:\Projects\BeaconEDC\BeaconEDC\Areas\DataEntry\Controllers\EngineController.cs:line 312 at lambda_method(Closure , ControllerBase , Object[] ) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c.b__9_0(IAsyncResult asyncResult, ActionInvocation innerInvokeState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass11_0.b__0() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass11_2.b__2() at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_6.b__4() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_1.b__1(IAsyncResult asyncResult)
现在,我在很多地方写入数据库,但它总是在同一个地方报告这一点。但是我在代码的那部分中没有看到使用任何缓存存储库中的任何内容。我实际上只是创建一个新对象,向其中添加一堆东西(字符串、长整数、整数或日期),将其添加到上下文中,然后保存更改。
为了让事情更令人沮丧,我从来没有能够在 Visual Studio 中重现这一点。只发生在服务器上。
所以我的问题是,有没有办法从该异常中获取更多信息?有什么方法可以准确地说出它在说什么两个对象?
这是失败的地方:
HatterasGlobal global = repo.HatterasGlobal(iid, caseId, "FormStatus");
if (global == null)
{
global = new HatterasGlobal();
global.CaseID = caseId;
global.GlobalName = "FormStatus";
global.Mode = 1;
global.Value = "C";
global.Modified = DateTime.Now;
global.HatterasInstrumentID = iid;
global.StudyId = studyId;
global.SubjectId = subjectId;
global.FormIteration = formIteration;
repo.Add(global);
}
else
{
global.Value = "C";
global.Modified = DateTime.Now;
repo.SaveChanges();
}
// set the date complete
HatterasGlobal dateGlobal = repo.HatterasGlobal(studyForm.Form.IID, caseId, "DateComplete");
if (dateGlobal == null)
{
dateGlobal = new HatterasGlobal();
dateGlobal.CaseID = caseId;
dateGlobal.GlobalName = "DateComplete";
dateGlobal.Mode = 1;
dateGlobal.Value = DateTime.Now.ToShortDateString();
dateGlobal.Modified = DateTime.Now;
dateGlobal.HatterasInstrumentID = iid;
dateGlobal.StudyId = studyId;
dateGlobal.SubjectId = subjectId;
dateGlobal.FormIteration = formIteration;
repo.Add(dateGlobal);
}
else
{
dateGlobal.Value = DateTime.Now.ToShortDateString();
dateGlobal.Modified = DateTime.Now;
repo.SaveChanges();
}
它实际上在堆栈跟踪中轰炸的那一行是这个人:
HatterasGlobal dateGlobal = repo.HatterasGlobal(studyForm.Form.IID, caseId, "DateComplete");
但我怀疑 repo.Add(global) 有问题。所做的就是:
public void Add(HatterasGlobal global)
{
_context.HatterasGlobals.Add(global);
_context.SaveChanges();
}
这里是注册 Context 的地方(Unity):
container.RegisterType<CMSContext>(new PerRequestLifetimeManager(), new InjectionConstructor());
...
container.RegisterType<IDataEntryRepository, CachedDataEntryRepository>(new PerRequestLifetimeManager(), new InjectionConstructor(typeof(CMSContext)));
在 repo 中,上下文是这样初始化的:
protected CMSContext _context;
public EFDataEntryRepository(CMSContext context)
{
this._context = context;
}
(EFDataEntryRepository 是 CachedDataEntryRepository 的基类。)
这是我如何进行缓存的示例:
public override Study Study(long id)
{
var study = HttpRuntime.Cache["Study-" + id + "-" + HttpContext.Current.User.Identity.Name] as Study;
if (study == null)
{
lock (CacheLockObject)
{
study = HttpRuntime.Cache["Study-" + id + "-" + HttpContext.Current.User.Identity.Name] as Study;
if (study == null)
{
study = base.Study(id);
if (study != null) HttpRuntime.Cache.Insert("Study-" + id + "-" + HttpContext.Current.User.Identity.Name, study, null, _absolute, _sliding);
}
}
}
return study;
}
这有帮助吗?
【问题讨论】:
-
抛出这个的代码是什么样的?我认为它与您的缓存存储库无关,看起来您正在混合上下文
-
您必须包含一些代码。对于新实体,“向其中添加一堆东西(字符串、长整数、整数或日期)”不会导致此错误。
-
嘿,对不起,让我看看我可以在那里注入什么代码。我正在使用 Unity 注入上下文,所以它应该都来自同一个上下文。
标签: c# entity-framework caching