【问题标题】:Entity framework error when binding entities to multiple database contexts将实体绑定到多个数据库上下文时出现实体框架错误
【发布时间】:2012-07-25 14:45:29
【问题描述】:

我在我的 MVC 应用程序中找不到正确的方法来绑定存储库和所有 EF 相关数据。下面的示例为每个 IRepository 创建新的 DbContext,这给了我错误

一个实体对象不能被多个实例引用 IEntityChangeTracker

出现此错误是因为我的实体在不同的上下文中。例如代码(它在实体中)将给出错误

var user = new User();
_userRepository.Insert(user) 

var order = new Order();
order.User = user;
_orderRepository.Insert(order) 
_unitOfWork.Commit();

如果我改变了

kernel.Bind(typeof(DbContext)).ToMethod(context => new DbContext(connectionString));

kernel.Bind(typeof(DbContext)).ToMethod(context => new DbContext(connectionString)).InRequestScope();

我得到错误

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

如果我在单独的线程中使用 ServiceRepository。

也许有人知道解决方案?

var connectionString = ConfigurationManager.ConnectionStrings["Entities"].ConnectionString;            
kernel.Bind(typeof(DbContext)).ToMethod(context => new DbContext(connectionString));            
kernel.Bind<IObjectSetFactory>().ToMethod(c => kernel.Get<DbContextAdapter>());
kernel.Bind<IObjectContext>().ToMethod(c => kernel.Get<DbContextAdapter>());  
kernel.Bind(typeof(IUnitOfWork)).To(typeof(UnitOfWork));
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
kernel.Bind<IServiceRepository>().To<ServiceRepository>();


 public interface IServiceRepository
    {
        UserDetail GetUser(int id);
        User GetUser(string email);
        User GetUser(string email, string password);
        OrderDetail GetOrder(string id);
        IEnumerable<OrderDetail> GetOrders(int userId);
        IEnumerable<Product> GetProducts();
        UserDetail GetParentUser(string partialEmail);
        IEnumerable<UserDetail> GetChildUsers(int parentId);
        IEnumerable<Statistic> GetStatisticForCurrentMonth(string ip);
        void InsertStatistic(QueueItem queueItem);
        void InsertStatistic();
        void Commit();
        void AddUser(User model);
        User AddUser(string firstName, string lastName, string email, string password, string country, int? parentId = null, DateTime? dateStamp = null);
        void AddOrder(Order order);
        void DeleteUser(int id);
        void DeleteUser(string email);
        bool OrderManager(PaymentProcessorOrder order, out User newUser, out Order newOrder);
        User AuthenticatedUser();
        string AuthenticatedUserEmail();
        bool ValidateUser(string email, string password);
        string GetPassword(string email);
    }


 public class ServiceRepository : IServiceRepository
    {
        private readonly IRepository<User> _userRepository;
        private readonly IRepository<Order> _orderRepository;
        private readonly IRepository<UserDetail> _userDetailRepository;
        private readonly IRepository<Statistic> _statisticRepository;
        private readonly IRepository<Product> _productRepository;
        private readonly IRepository<OrderDetail> _orderDetailRepository;
        private readonly IUnitOfWork _unitOfWork;
        private static readonly object Locker = new object();

  public ServiceRepository(IRepository<User> userRepository, IRepository<Statistic> statisticRepository, IRepository<UserDetail> userDetailRepository, IRepository<Order> orderRepository, IUnitOfWork unitOfWork, IRepository<OrderDetail> orderDetailRepository, IRepository<Product> productRepository)
        {
            _unitOfWork = unitOfWork;
            _userRepository = userRepository;
            _statisticRepository = statisticRepository;
            _userDetailRepository = userDetailRepository;
            _orderRepository = orderRepository;
            _orderDetailRepository = orderDetailRepository;
            _productRepository = productRepository;
        }

//Skip code
}

【问题讨论】:

    标签: c# asp.net-mvc entity-framework-4 ninject repository-pattern


    【解决方案1】:

    您不应该在 ASP.NET 应用程序中使用线程,因为它会给您带来很多问题。例如。当 IIS 回收您的应用程序池或暂停应用程序时,您的线程将被终止,使您的应用程序处于不一致的状态。或者您的线程中未捕获的异常可能会破坏您的整个应用程序。

    通常,您应该在单独的服务应用程序中实现异步事物,以便 IIS 只需发送一些消息,这些消息将被此服务异步处理。这也将解决您的问题,因为您可以为每条消息使用其他 DbContext。

    如果您真的想使用后台线程,那么您必须为您的请求和线程使用不同的 DbContext 绑定。例如

    kernel.Bind(typeof(DbContext)).ToMethod(context => new DbContext(connectionString)).InRequestScope();
    kernel.Bind(typeof(DbContext)).ToMethod(context => new DbContext(connectionString)).WhenInjectedInto<MyTask>();
    

    但这意味着您不能将实体从请求 DbContext 传递到后台线程上下文。

    【讨论】:

      【解决方案2】:

      您不应该将对象从一个 DbContext 传递到另一个。这在 EF 中不受支持(除非您分离和附加)。

      我建议在每个存储库中使用相同的 DbContext,并将存储库保持在同一个线程上。

      【讨论】:

      • 我不想将对象从一个 DbContext 传递到另一个,我想将它们保存在一个 DbContext 中。所以我在问如何做到这一点。
      • 我看到你在做什么,是为每个 repo 创建一个 DbContext,对吗?
      • 如果您将对象从一个存储库传递到另一个存储库,每个存储库都有一个 DbContext,那么您就是“将对象从一个 DbContext 传递到另一个”
      【解决方案3】:

      您在这里遇到的问题是使用多个存储库,当您处理一个存储库时,它也会处理 DbContext。您认为可以使用 DbContext 的单例实例(或每个会话)是对的

      Ninject: Singleton binding syntax?

      但是,在您处置存储库时,您需要以下内容:

      public void Dispose(bool AllResources)
      {
           if(AllResources)
           {
                _context.Dispose();
           }
           //Clean-up other resources
      }
      

      您可以使用的其他方法之一是将 Disposable 放在您的工厂中,这样当您执行多个存储库时,您将拥有:

      using(var RepoFactory = new RepositoryContextFactory())
      {
           var repo1 = RepositoryOne(RepoFactory.FetchContext());
           var repo2 = RepositoryTwo(RepoFactory.FetchContext());
           //Do work
      }  //Your context would then be disposed of in the closure of the using across all Repositories instead of per repository which will allow you to reuse the same context across multiple repositories.
      

      希望这在一定程度上有所帮助。

      【讨论】:

      • 我写过我已经尝试过 .InRequestScope() 但我认为由于多线程,无法在 Web 应用程序中使用 DbContext 的单例实例。
      • 问题是您的存储库在存储库关闭后正在删除您的上下文,因此您收到的对象错误已被处理。您必须在所有存储库中使用单个上下文,并将存储库模式更改为不处理 DbContext !!!!!!它必须在存储库模式之外关闭。
      • Tomas:至于您认为 Web 应用程序中的单个 DbContext 实例是一件坏事的评论,您是对的。我更喜欢的模式是每个请求一个实例,尽管您必须确定不要使用来自多个线程的实例。
      猜你喜欢
      • 1970-01-01
      • 2015-03-23
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多