我在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
}
答案 0 :(得分:2)
您不应该在ASP.NET应用程序中使用线程,因为它会给您带来很多问题。例如。当IIS回收您的App Pool或挂起应用程序时,您的线程将被终止,使您的应用程序处于不一致状态。或者你线程中一个未捕获的异常可以拆除你的整个应用程序。
通常,您应该在单独的服务应用程序中实现异步内容,以便IIS只需发送一些消息,这些消息将被异步处理为此服务。这也将解决您的问题,因为您可以为每条消息使用其他DbContext。
如果你真的想使用后台线程,那么你必须为你的请求和线程使用不同的DbContext绑定。 E.g。
kernel.Bind(typeof(DbContext)).ToMethod(context => new DbContext(connectionString)).InRequestScope();
kernel.Bind(typeof(DbContext)).ToMethod(context => new DbContext(connectionString)).WhenInjectedInto<MyTask>();
但这意味着您无法将请求DbContext中的实体传递给后台线程上下文。
答案 1 :(得分:0)
您不应该将对象从一个DbContext传递到另一个DbContext。 EF不支持此功能(分离和附加时除外)。
我建议在每个存储库中使用相同的DbContext,并将存储库保存在同一个线程中。
答案 2 :(得分:0)
这里遇到的问题是当你处理一个它也处理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.
希望这在某种程度上有所帮助。