You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Entity Framework提示对象附加到不同ObjectContext实例?

问题:WebForms中Scoped注入DbContext引发跨上下文异常

场景描述

  • 基于.NET 4.7.2的WebForms应用,支持从模态窗口、主窗口两种UI场景调用代码
  • MyClass通过依赖注入注入到aspx后台,myDbContext同样通过依赖注入注入到MyClass,二者均使用.AddScoped()方法配置生命周期
  • 模态窗口调用MyMethod时功能正常,但主窗口调用时,执行myDbContext.myDbTable.Attach(myObject)抛出异常:

The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects

代码示例

public class MyClass : IMyClass
{    
    private readonly DTSEFContainer myDbContext;

    public MyClass(DTSEFContainer context)
    {
        myDbContext = context;
    }

    public void MyMethod()
    {
        var myObject = myDbContext.myDbTable.Where(a => a.ID == 1234).FirstOrDefault();

        if (myObject != null)
        {
            myObject.Name = name;
            myObject.Updated = DateTime.Now();

            myDbContext.myDbTable.Attach(myObject);
            myDbContext.myDbTable.AddOrUpdate(myObject);    
            myDbContext.SaveChanges();                
        }
    }
}

问题根源

WebForms的页面生命周期和ASP.NET Core差异很大,默认情况下Scoped生命周期在WebForms中无法严格按请求隔离。主窗口可能存在页面回发、视图状态缓存的情况:要么你代码里的Attach属于多余操作(从当前上下文查出来的实体已经被跟踪,手动Attach会触发冲突),要么主窗口的旧实体(属于之前的上下文实例)被视图状态保存,后续回发时和新注入的Scoped上下文产生冲突。

修复方案

  1. 移除冗余的Attach和AddOrUpdate调用
    从当前myDbContext查询得到的myObject本身就处于上下文跟踪状态,修改属性后直接调用SaveChanges即可完成更新,不需要额外的Attach或AddOrUpdate。修改后的代码:
    public void MyMethod()
    {
        var myObject = myDbContext.myDbTable.Where(a => a.ID == 1234).FirstOrDefault();
    
        if (myObject != null)
        {
            myObject.Name = name;
            myObject.Updated = DateTime.Now;
    
            // 移除不必要的Attach和AddOrUpdate
            myDbContext.SaveChanges();                
        }
    }
    
  2. 确保Scoped上下文的Web请求边界配置
    如果使用第三方DI容器(比如Autofac),需要明确配置Scoped生命周期以HttpContext为边界,确保同一个请求内只创建一个myDbContext实例;如果是自定义DI实现,要借助HttpContext.Current来存储Scoped实例,避免同一请求内多次实例化上下文。
  3. 排查主窗口的视图状态问题
    检查主窗口是否通过视图状态保存了myObject相关数据,若存在,可禁用该部分的视图状态,或者在使用实体前先判断它是否被当前上下文跟踪(可通过myDbContext.Entry(myObject).State查看状态),如果属于未跟踪或属于其他上下文,可重新查询实体再进行修改。

内容的提问来源于stack exchange,提问作者Hoodlum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:52:37