1

我在我的 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
}
4

3 回答 3

2

您不应该在 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 传递到后台线程上下文。

于 2012-07-25T15:29:58.023 回答
0

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

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

于 2012-07-25T14:53:44.190 回答
0

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

Ninject:单例绑定语法?

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

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.

希望这在某种程度上有所帮助。

于 2012-07-25T15:11:45.803 回答