为所有存储库创建一个上下文导致错误

时间:2016-02-19 13:01:25

标签: entity-framework dbcontext

我正在尝试在所有存储库之间共享我的DBcontext,

所以这是我的workflowContext

public class WorkflowContext : DbContext {
    public WorkflowContext()
        : base("name=WorkflowContext") {
    }

    public DbSet<Instance> Instances { get; set; }
    public DbSet<Task> Tasks { get; set; }
}

这是baseRepo

public class WorkFlowBaseRepo {
    protected static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    internal WorkflowContext Db;

    public WorkFlowBaseRepo() {
        Db = new WorkflowContext();
    }

    internal void SetState(object instance, EntityState state) {
        Log.DebugFormat("setting {0} state", ObjectContext.GetObjectType(instance.GetType()));
        try {
            if (Db.Entry(instance).State != EntityState.Added) {
                Db.Entry(instance).State = state;
            }
        } catch (Exception e) {
            Log.Error("Error setting state", e);
        }
    }

    internal int SaveChanges() {
        Log.DebugFormat("Saving changes");
        try {
            return Db.SaveChanges();
        } catch (Exception e) {
            Log.Error("Error Saving", e);
            return -1;
        }
    }

    internal void Dispose() {
        try {
            Db.Dispose();
        } catch (Exception e) {
            Log.Error("Error disposing", e);
        }
    }
}

然后repo继承自WorkflowBaseRepo,这是一个回购的例子:

public class InstanceRepo : WorkFlowBaseRepo {
    private readonly DocumentRepo _documentRepo;
    private readonly TaskRepo _taskRepo;
    private readonly WorkflowRepo _workflowRepo;
    private readonly MailService _mailService;
    private readonly QService _qService;
    private readonly OService _oService;
    public InstanceRepo() {
        _workflowRepo = new WorkflowRepo();
        _mailService = new MailService();
        _documentRepo = new DocumentRepo();
        _taskRepo = new TaskRepo();
        _oService = new OService();
        _qService = new QService();
    }

    internal List<Instance> GetAll() {
        Log.DebugFormat("Getting all Instances");
        try {
            return Db.Instances.ToList();
        } catch (Exception e) {
            Log.Error("Error getting all instance", e);
            return null;
        }
    }

    internal Instance GetById(int id) {
        Log.DebugFormat("Getting instance {0}", id);
        try {
            var instance = Db.Instances.Find(id);


            var docid = instance.Document != null ? instance.Document.Id : -1;
            instance.Document = _documentRepo.GetByDocumentId(instance.ObjectId);

            if (instance.Document.Id != docid) {
                Db.SaveChanges();
            }

            return instance;
        } catch (Exception e) {
            Log.Error("Error finding instance", e);
            return null;
        }
    }

    internal Instance AddInstance(InstancePostDto instance) {
        // code 
    }

    internal Instance RemoveInstance(Instance instance) {
        Log.DebugFormat("Removing Instance {0}", instance.Id);
        try {
            return Db.Instances.Remove(instance);
        } catch (Exception e) {
            Log.Error("Error removing instance", e);
            return null;
        }
    }

    internal void SetState(Instance instance, EntityState state) {
        try {
            base.SetState(instance, state);
            instance.UdatedDate = DateTime.Now;
        } catch (Exception e) {
            Log.Error("Error", e);
        }
    }

    internal bool InstanceExists(int id) {
        try {
            return Db.Instances.Count(e => e.Id == id) > 0;
        } catch (Exception e) {
            Log.Error("Error", e);
            return false;
        }
    }
}

但是现在我在更新The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.

时遇到以下错误

知道为什么会这样吗?以及如何解决它?

1 个答案:

答案 0 :(得分:3)

您没有在您的存储库中共享DbContext,每个存储库都从基类的构造函数中获取它的新实例:

public WorkFlowBaseRepo() {
    Db = new WorkflowContext();
}

这就是为什么您会看到相关对象附加到上下文的不同实例的异常。您的InstanceRepo实际上有7个WorkflowContext的不同实例。

解决此问题的最佳方法是使用依赖注入容器(也称为控制容器的反转),如SimpleInjector,StructureMap,Ninject,Autofac,Castle Windsor ......还有其他选择。使用其中一个来启用构造函数注入,然后将DbContext实例注册为作用域依赖项。这样,您将在应用程序中获得其中一个每个作用域操作(例如,在Web应用程序中,&#34;范围&#34;将意味着单个请求)。

像这样(伪代码)

var container = new Container();
container.RegisterScoped<WorkflowContext>(x => new WorkflowContext());
container.Verify();
public class WorkFlowBaseRepo {

    internal WorkflowContext Db;

    public WorkFlowBaseRepo(WorkflowContext db) {
        Db = db;
    }

然后,您的容器将确保所有repos在同一范围内收到WorkflowContext依赖项的相同引用实例。

注意我是如何使DbContext成为构造函数的参数。如果你真的厌恶IoC,你可能会得到类似的东西:

public InstanceRepo(WorkflowContext db) {
    Db = db ?? new WorkflowContext();
    _workflowRepo = new WorkflowRepo(Db);
    _mailService = new MailService(Db);
    _documentRepo = new DocumentRepo(Db);
    _taskRepo = new TaskRepo(Db);
    _oService = new OService(Db);
    _qService = new QService(Db);
}

通过以上操作,您的InstanceRepo正在与其他所有回购商共享其DbContext的实例。但请注意,在这里,我们仍然是#34;构造函数注入&#34;一个依赖项,即使没有IoC容器。

相关问题