简体   繁体   English

无法找出哪些两个对象附​​加到不同的ObjectContext对象

[英]Cannot figure out which two objects are attached to different ObjectContext objects

So I recently took a system (MVC/Entity Framework) that we have and added in a bunch of Cached Repositories to speed it up. 因此,我最近使用了一个已有的系统(MVC /实体框架),并添加了一堆缓存存储库以加快速度。 It seemed to work fine in testing, however when we pushed it out we have been randomly getting this error from random users: 它在测试中似乎工作正常,但是当我们推出它时,我们是从随机用户那里随机得到此错误的:

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)

Now, I write to the database in lots of places, but it always reports this in the same place. 现在,我在很多地方都写了数据库,但是它总是在同一个地方报告这个。 But there is nothing I'm seeing in that part of the code that use anything from any of the cached repositories. 但是在那部分代码中我没有看到任何使用任何缓存存储库中的任何内容的东西。 I literally just create a new object, add a bunch of stuff to it (that are either strings, longs, integers, or dates), add it to the context, and save changes. 实际上,我只是创建一个新对象,向其中添加一堆东西(可以是字符串,长整数,整数或日期),将其添加到上下文中,然后保存更改。

To make things more frustrating, I've never been able to reproduce this in Visual Studio. 为了使事情更加令人沮丧,我从来没有能够在Visual Studio中重现它。 Only occurs on the server. 仅在服务器上发生。

So my question is, is there any way of getting more information out of that exception? 所以我的问题是,有什么办法可以从异常中获取更多信息? Some way of telling exactly what two objects it is talking about? 确切说出正在谈论的两个对象的某种方式?

Here is the bit where it is failing: 这是失败的地方:

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();
}

The line that it is actually bombing on in the stack trace is this guy: 它实际上在堆栈跟踪中轰炸的那一行是这个家伙:

HatterasGlobal dateGlobal = repo.HatterasGlobal(studyForm.Form.IID, caseId, "DateComplete");

But I suspect it is having a problem with repo.Add(global). 但是我怀疑repo.Add(global)有问题。 All that does is this: 所有这些是这样的:

public void Add(HatterasGlobal global)
{
    _context.HatterasGlobals.Add(global);
    _context.SaveChanges();
}

Here is where the Context is registered (Unity): 这是注册上下文(统一)的位置:

container.RegisterType<CMSContext>(new PerRequestLifetimeManager(), new InjectionConstructor());
...
container.RegisterType<IDataEntryRepository, CachedDataEntryRepository>(new PerRequestLifetimeManager(), new InjectionConstructor(typeof(CMSContext)));

Inside the repo, the context is initialized like so: 在仓库内,上下文被初始化为:

protected CMSContext _context;
public EFDataEntryRepository(CMSContext context)
{
   this._context = context;
}

(The EFDataEntryRepository is the base class for CachedDataEntryRepository.) (EFDataEntryRepository是CachedDataEntryRepository的基类。)

Here is an example of how I'm doing the caching: 这是我如何进行缓存的示例:

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

Does that help? 有帮助吗?

"at ClinicalCMS.Domain.CMSContext.SaveChanges() ..." You need to dive further down the exception stack past the "...", that will be the meat of the problem. “在ClinicalCMS.Domain.CMSContext.SaveChanges()处...”您需要进一步深入异常堆栈,使其超过“ ...”,这将成为问题的症结所在。

The usual culprit for this will be code that is passing entities around. 通常的罪魁祸首是在周围传递实体的代码。 As a simple example: 作为一个简单的例子:

public IEnumerable<RelatedEntity> LoadRelated()
{
    using (var context = new MyDbContext())
    {
        return context.RelatedEntities.ToList();
    }
}

public void SaveEntity(ParentEntity entity)
{
    using (var context = new MyDbContext())
    {
        context.ParentEntities.Add(entity);
        context.SaveChanges()
    }
}

public void SomeAction(ParentEntityViewModel viewModel)
{
    var relatedEntities = LoadRelated();
    var relatedEntity = relatedEntities
        .OrderBy(x => x.ApplicableDate)
        .First(x => x.ApplicableDate >= DateTime.Now);
    var newEntity = new ParentEntity
    {
        Name = viewModel.Name,
        RelatedEntity = relatedEntity
     };
     SaveEntity(newEntity);
}

... again, a bare-bones example for demonstration. ……再次是一个简单的演示示例。 This normally manifests when code is using things like Repository patterns which are either leveraging different bounded contexts (ie different DbContexts that load the same entities) or where the DbContext in question has multiple instances declared such as a different lifetime scope depending on whether you use an IoC Container or not. 这通常在代码使用诸如存储库模式之类的东西时体现出来,它们要么利用不同的有界上下文(即,加载相同实体的不同DbContext),要么所讨论的DbContext声明了多个实例,例如不同的生存期范围,具体取决于您是否使用了是否有IoC容器。

The above example is using 2 different instances of a DbContext. 上面的示例使用了DbContext的2个不同实例。 The related entities were loaded in the first, but the Save uses a second. 相关实体在第一个中加载,但保存使用第二个。 When we create a parent entity and associate an entity still tracked by the first and then give it to the second, we would get that error you are seeing. 当我们创建父实体并关联仍被第一个实体跟踪的实体,然后将其分配给第二个实体时,您将看到该错误。

Given you are seeing the error in production but not in testing I would suspect one of two things: 鉴于您看到的是生产中的错误,但没有测试中的错误,因此我怀疑以下两种情况之一:

  1. This is a rare scenario that users are tripping that you aren't reproducing when testing. 这是一种罕见的情况,用户跳闸,您在测试时不会重现。
  2. This is a concurrent session issue and your caching is doing something naughty. 这是一个并发的会话问题,您的缓存做得很顽皮。

I'm leaning towards #2 given caching and entities are never something that should really ever be done. 我倾向于#2,因为缓存和实体从来都不是真正应该做的事情。 If your DbContext is scoped per-request via an EF context, and you are loading entities then throwing them into a static cache, while that request is active, other requests which will spawn other DbContexts might pick out entities from a cache. 如果您的DbContext是通过EF上下文按请求确定作用域的,并且您正在加载实体,然后将它们扔到静态缓存中,而该请求处于活动状态,则其他产生DbContext的请求可能会从缓存中挑选实体。 These entities would be associated with the other request's DbContext and would likely result in errors like what you are seeing. 这些实体将与另一个请求的DbContext关联,并可能导致类似您所看到的错误。 Any caching you do should only ever be done at a session state, not static / cross-session. 您所做的任何缓存都只能在会话状态下进行,而不能是静态/交叉会话。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法定义两个对象之间的关系,因为它们附加到不同的ObjectContext对象Entity Framework - The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects Entity Framework 无法定义两个对象之间的关系,因为它们附加到不同的 ObjectContext 对象 - The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects “无法定义两个对象之间的关系,因为它们被附加到不同的ObjectContext对象。” -错误 - 'The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.' - Error 引发异常:因为两个对象附​​加到不同的ObjectContext对象,所以无法定义它们之间的关系 - Exception thrown: The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects EF4错误:无法定义两个对象之间的关系,因为它们附加到不同的ObjectContext对象 - EF4 error:The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects 实体框架v4 - 无法定义两个对象之间的关系,因为它们附加到不同的ObjectContext对象 - Entity Framework v4 - The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects 无法定义两个对象之间的关系,因为它们已附加到不同的ObjectContext对象 - The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects 实体框架:“无法定义两个对象之间的关系,因为它们附加到不同的 ObjectContext 对象。” - Entity Framework: “The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.” 无法定义关系,因为它们已附加到不同的ObjectContext对象 - Relationship cannot be defined because they are attached to different ObjectContext objects InvalidOperationException由于存在不同的ObjectContext对象 - InvalidOperationException because of different ObjectContext objects
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM