使用Unity时不会处理EF Context

时间:2016-03-15 13:49:55

标签: c# .net entity-framework unity-container

我正在尝试实现一个存储库模式,但遇到了我的上下文的困难。当我按照预期开始调试我的UI显示时,所有数据都会按原样返回,但是当我尝试过滤数据时,我从EF获得异常,通知我“已经有一个与此命令关联的开放DataReader ......”

init

我的存储库界面如下所示:

public static class UnityConfig
{
    public static UnityContainer Container;
    public static void RegisterComponents()
    {
        var container = new UnityContainer();
        Container = container;

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());

        container.RegisterType<MyContext>(new PerRequestLifetimeManager());

        container.AddNewExtension<RepositoryModule>();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }
}

public class RepositoryModule : UnityContainerExtension
{
    protected override void Initialize()
    {
        Container.RegisterType<IBusinessClass>(
            new PerRequestLifetimeManager()),
            new InjectionFactory(
                c => new BusinessClass 
                    c.Resolve<IRepository<EntityOne>>(),
                    c.Resolve<IRepository<EntityTwo>>());
        );

        Container.RegisterType<IRepository<EntityOne>, RepoOne>(
            new PerRequestLifetimeManager(),
            new InjectionFactory(
                c => new RepoOne(c.Resolve<MyContext>())));

        Container.RegisterType<IRepository<EntityTwo>, RepoTwo>(
            new PerRequestLifetimeManager(),
            new InjectionFactory(
                c => new RepoTwo(c.Resolve<MyContext>())));         
    }
}

存储库的实现使用了一个抽象类来保存和处理功能:

public interface IRepository<T> where T : class
{

    IQueryable<T> Query { get; }
    T GetByID(int id);

    IEnumerable<T> GetAll();

    T Insert(T entity);

    void Update(T entity);

    void Delete(T entity);

    void Save();
}

实际的存储库看起来像这样:

public abstract class BaseRepository : IDisposable
{    
    protected MyContext context;

    protected BaseRepository(MyContext context)
    {
        this.context = context;
    }

    /// <summary>
    /// Save changes
    /// </summary>
    public void Save()
    {
        context.SaveChanges();
    }

    #region Dispose

    private bool disposed = false;

    protected virtual void Dispose(bool diposing)
    {
        if (!disposed)
        {
            context.Dispose();
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion
}

我假设我的背景没有被处理,但我无法弄清楚原因。我错过了什么或者我完全搞砸了这里的建筑吗?

[编辑] 代码正在处理第一次加载。只有当我回到存储库才能获得我遇到问题的过滤后的数据子集时。

我已经更新了解决方案,使用一个简单的工厂来获取存储库,因此Unity中的分配现在看起来像这样:

public class RepoOne : BaseRepository, IRepository<EntityOne>
{
    public RepoOne(MyContext context)
        : base(context)
    {
        this.context = context;
    }

    public IQueryable<EntityOne> Query => context.EntityOne;

    public EntityOne GetByID(int id)
    {
        return context.EntityOne.Find(id);
    }

    public IEnumerable<EntityOne> GetAll()
    {
        return context.EntityOne.ToList();
    }

    public EntityOne Insert(EntityOne entity)
    {
        return context.EntityOne.Add(entity);
    }

    public void Update(EntityOne entity)
    {
        var entityOne = context.EntityOne.Find(entity.ID);
    }

    public void Delete(EntityOne entity)
    {
        throw new NotImplementedException();
    }
}

和工厂:

            Container.RegisterType<IRepository<EntityOne>>(
            new PerRequestLifetimeManager(),
            new InjectionFactory(
                c =>
                    RepositoryFactory<EntityOne>.GetRepository(
                        "EntityOne",
                        c.Resolve<MyContext>())));

@vendettamit:我的PerRequestLifetimeManager

public static class RepositoryFactory<T> where T : class 
{
    public static IRepository<T> GetRepository(string entityType,           PollBookMonitorContext context)
    {
        switch (entityType)
        {
            case "EntityOne":
                    return (IRepository<T>) new RepoOne(context);
            case "EntityTwo":
                    return (IRepository<T>) new RepoTwo(context);
            default: return null;
        }

非常感谢任何帮助。

我的代码终于有效了。我刚刚发现我查询的其中一个表是整天都在处理大量数据,据我所知,这会导致EF从数据库中读取数据的方式产生负面影响。或许我在没注意的时候解决了这个问题。

3 个答案:

答案 0 :(得分:1)

我认为问题在于:

private bool disposed = false;

protected virtual void Dispose(bool diposing)
{
    if (!disposed)
    {
        context.Dispose();
    }
}

在if而不是使用全局字段中,使用参数&#34; disposing&#34;

 protected virtual void Dispose(bool diposing)
 {
        if (!disposing) return;        
        context.Dispose();
 }

答案 1 :(得分:1)

使用PerRequestLifetimeManager需要注册UnityPerRequestHttpModule。根据{{​​3}},

  

对于HTTP请求完成时自动处理的注册类型的实例,请确保将UnityPerRequestHttpModule注册到Web应用程序。

检查UnityConfig.cs,确保它没有注册模块。模块注册应在Unity.Mvc.Activator.cs中完成。或者,您也可以尝试在启动文件(OWIN)中注册模块:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnityWebActivator), "Start")]

答案 2 :(得分:1)

您应该执行以下操作:

public interface IRepository : IDisposable
{
     // Your code.
}

然后在您的数据上下文中,它将实现您的部署:

public void Dispose()
{
     Dispose(true);
     GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
     if(!disposed)
     {
          if(disposing)
          {     
              component.Dispose();
          }
          disposed = true;
     }
}

~DataContext() { Dispose(false); }

如果你真的想要,你可以稍微清理一下你的架构。你可以做的一种方法就是这样:

public interface IRepository
{
     // Your method operation.
}

public interface IFactory : IRepositoryFactory
{
     // Container factory, to interject between multiple data context.
}

public interface IRepositoryFactory
{
     IRepository Create();
}

public class DataContext : DbContext, IRepository
{
     // Entity Framework and Repository concreete implementation.
}

public class DataContextFactory : IFactory
{
     public IRepository Create()
     {
         return new DataContext();
     }
}

然后,您将使用Unity映射工厂,然后您只需在方法中调用:

using(var context = Create())
     return context.List<Model>(....);