我的存储库类和控制器类之间的协调使用相同的Context对象

时间:2015-02-05 15:06:11

标签: c# asp.net asp.net-mvc entity-framework-6 unit-of-work

我正在开发一个asp.net mvc Web应用程序。现在我创建了多个存储库类,例如我有以下抽象存储库类: -

public interface ISkillRepository : IDisposable
{//code goes here..

&安培;

public interface IStaffRepository : IDisposable
{//code goes here

和模型存储库: -

public class SkillRepository :  ISkillRepository , IDisposable
                {
 private SkillManagementEntities context = new SkillManagementEntities();
    //code goes here

&安培;

public class StaffRepository :  IStaffRepository , IDisposable
                {
                    private SkillManagementEntities context = new SkillManagementEntities();

现在在y控制器中我正在初始化并创建回购,如下所示: -

 public class SkillController : Controller
    {

        private ISkillRepository skillRepository;


      public SkillController() : this(new SkillRepository()) {}

      public SkillController(ISkillRepository repository)
      {
          skillRepository = repository;
      }

但目前我的应用程序中出现以下错误:

The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.

问题是我需要通过回购和控制器传递相同的上下文。任何人都可以这样做: -

  1. 我如何在一个模型仓库中使用相同的上下文类引用另一个仓库。例如,在Staff存储库中引用技能存储库?

  2. 我如何在控制器类中引用多个repos,但同时在它们之间传递相同的上下文对象,所以如果我发出save(),它会将所有语句包装在一个事务中。例如,让我的技巧控制器参考技巧和技巧。员工回购使用相同的上下文对象?

  3. 由于

    修改 我创建了以下工作单元类: -

     public class UnitOfWork : IDisposable
        {
            private SkillManagementEntities context = new SkillManagementEntities();
            private SkillRepository skillRepository;
            private StaffRepository staffRepository;
            private SecurityRoleRepository securityroleRepository;
            public SkillRepository SkillRepository
            {
                get
                {
    
                    if (this.skillRepository == null)
                    {
                        this.skillRepository = new SkillRepository(context);
                    }
                    return skillRepository;
                }
            }
    
            public StaffRepository StaffRepository
            {
                get
                {
    
                    if (this.staffRepository == null)
                    {
                        this.staffRepository = new StaffRepository(context);
                    }
                    return staffRepository;
                }
            }
            public SecurityRoleRepository SecurityRoleRepository
            {
                get
                {
    
                    if (this.staffRepository == null)
                    {
                        this.staffRepository = new SecurityRoleRepository(context);
                    }
                    return securityroleRepository;
                }
            }
            public async Task Save()
            {
                await context.SaveChangesAsync();
            }
    
            private bool disposed = false;
    
            protected virtual void Dispose(bool disposing)
            {
                if (!this.disposed)
                {
                    if (disposing)
                    {
                        context.Dispose();
                    }
                }
                this.disposed = true;
            }
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
    }
    

    然后在我的回购中我做了以下事情: -

     public class SecurityRoleRepository :  ISecurityRoleRepository , IDisposable
            {
                private SkillManagementEntities context;// = new SkillManagementEntities();
    
                public SecurityRoleRepository(SkillManagementEntities context)
                {
                  this.context = context;
    

    在控制器类上,我将引用UnitOfWork,如下所示: -

       public class SecurityRoleController : Controller
        {
    
            private UnitOfWork unitOfWork = new UnitOfWork();
    
            public async Task<ActionResult> Index(string filter = null, int page = 1, int pageSize = 20, string sort = "Name", string sortdir = "ASC")
            {
    
                try
                {
                    var records = new PagedList<SecurityRole>();
                    ViewBag.filter = filter;
                    records.Content = await unitOfWork.SecurityRoleRepository.GetSecurityRoleForGrid(filter, page, pageSize, sort, sortdir).ToListAsync();
    

    现在我面临的一个问题是,我如何能够从另一个回购中引用回购?例如,我如何在SecurityRole仓库中引用技能仓库?

    编辑最终 我做了以下步骤: - 1.我安装

    Install-Package Ninject.MVC5 
    

    2。然后我创建了以下依赖类: -

        public class YourDependencyResolverClass : IDependencyResolver
    {
        private IKernel kernel;
    
        public YourDependencyResolverClass()
        {
            kernel = new StandardKernel();
            AddBindings();
        }
    
        public object GetService(Type serviceType)
        {
            return kernel.TryGet(serviceType);
        }
        public IEnumerable<object> GetServices(Type serviceType)
        {
            return kernel.GetAll(serviceType);
        }
    
    
        private void AddBindings()
        {
            kernel.Bind<ISkillRepository>().To<SkillRepository>();
            kernel.Bind<IStaffRepository>().To<StaffRepository>();
            kernel.Bind<ISecurityRoleRepository>().To<SecurityRoleRepository>();
            kernel.Bind<ICustomerRepository>().To<CustomerRepository>();
            kernel.Bind<ISkillVersionHistoryRepository>().To<SkillVersionHistoryRepository>();
         }
    }
    }
    

    3.现在在我的SkillRepository类中,我将引用StaffRepository,如下所示: -

       public class SkillRepository :  ISkillRepository , IDisposable
                {
                    private SkillManagementEntities context ;
    
                    private IStaffRepository staffrepo = (IStaffRepository)DependencyResolver.Current.GetService(typeof(IStaffRepository));
                    public SkillRepository(SkillManagementEntities context)
                    {
                      this.context = context;
                    }
    

    最后在我的动作方法中,我将调用Uiteofwork类如下: -

     public class StaffController : Controller
        {
            //private SkillManagementEntities db = new SkillManagementEntities();
    
            UnitOfWork unitofwork = new UnitOfWork();
    
    
    
    
        public async Task<ActionResult> AutoComplete(string term)
          {
    
              var staff = await unitofwork.StaffRepository.GetAllActiveStaff(term).Select(a => new { label = a.SamAccUserName }).ToListAsync();
    
              return Json(staff, JsonRequestBehavior.AllowGet);
    

    和工人阶级的团结是: -

       public class UnitOfWork : IDisposable
            {
                private SkillManagementEntities context = new SkillManagementEntities();
                private SkillRepository skillRepository;
                private StaffRepository staffRepository;
                private SecurityRoleRepository securityroleRepository;
                private CustomerRepository customerRepository;
                private SkillVersionHistoryRepository SVH;
                public SkillRepository SkillRepository
                {
                    get
                    {
    
                        if (this.skillRepository == null)
                        {
                            this.skillRepository = new SkillRepository(context);
                        }
                        return skillRepository;
                    }
                }
    
                public StaffRepository StaffRepository
                {
                    get
                    {
    
                        if (this.staffRepository == null)
                        {
                            this.staffRepository = new StaffRepository(context);
                        }
                        return staffRepository;
                    }
                }
                public CustomerRepository CustomerRepository
                {
                    get
                    {
    
                        if (this.customerRepository == null)
                        {
                            this.customerRepository = new CustomerRepository(context);
                        }
                        return customerRepository;
                    }
                }
                public SecurityRoleRepository SecurityRoleRepository
                {
                    get
                    {
    
                        if (this.securityroleRepository == null)
                        {
                            this.securityroleRepository = new SecurityRoleRepository(context);
                        }
                        return securityroleRepository;
                    }
                }
                public SkillVersionHistoryRepository SkillVersionHistoryRepository 
                {
                    get
                    {
    
                        if (this.SVH == null)
                        {
                            this.SVH = new SkillVersionHistoryRepository(context);
                        }
                        return SVH;
                    }
                }
                public async Task Save()
                {
                    await context.SaveChangesAsync();
                }
    
                private bool disposed = false;
    
                protected virtual void Dispose(bool disposing)
                {
                    if (!this.disposed)
                    {
                        if (disposing)
                        {
                            context.Dispose();
                        }
                    }
                    this.disposed = true;
                }
    
                public void Dispose()
                {
                    Dispose(true);
                    GC.SuppressFinalize(this);
                }
            }
    

    所以,如果我使用unitefwork和DI的方法能保证我的所有语句都会在单个数据库事务中被扭曲,那么你能不能这样做? thnaks?

2 个答案:

答案 0 :(得分:2)

我们通过使用一个使用HttpContext作用于请求的单例共享一个上下文来处理这个问题:

    public MyContext GetContext()
    {
        if (System.Web.HttpContext.Current.Items["MyScopedContext"] == null)
        {
            System.Web.HttpContext.Current.Items["MyScopedContext"] = new MyContext();
        }

        return (MyContext)System.Web.HttpContext.Current.Items["MyScopedContext"];
    }

上下文对象(存储库)本身基本上包含一个工作单元。我上面添加的代码只是为您提供了一种在请求中运行的所有代码之间共享单个存储库的方法。如果您的存储库类是在Web应用程序的范围内定义的,则可以通过调用GetContext()方法替换SkillManagementEntities()的直接实例化。

另一方面,如果您的存储库是在异构应用程序共享的层中定义的,则可能需要从可以根据需要注入的工厂对象获取上下文。无论哪种方式,每个存储库创建一个新的上下文对象都会导致您的问题。

答案 1 :(得分:1)

不是答案:这个“使用DI”建议回答了一个不同的问题 - OP正在寻找“工作单元”模式 - 而基本情况(工作单元的生命周期与生命周期匹配)可以使用任何DI框架轻松解决请求/控制器的问题,管理多个工作单元或工作单元,使用寿命更长,更加困难,专用的“工作单元工厂”(sample usage)可能是解决方案。 / p>


通常当你使用接口/存储库和构造函数依赖注入时,你有一些依赖注入框架。您正在使用的一个很可能已经提供了“按HTTP请求”解析或允许轻松添加一个。

即。如果您使用Unity,则PerRequestLifetime生命周期管理器会对同一接口/对象进行所有.Resolve调用,以便为给定请求返回相同的实例。请参阅DI with Unity MSDN文章中的详细信息。

近似样本:

container.RegisterType<ISkillRepository, SkillRepository>();
container.RegisterType<IOtherRepository, OtherRepository>();
container.RegisterType<TheContext, TheContext>(new PerRequestLifetime());

通过这样的注册并假设您已经配置ASP.Net MVC以在创建控制器时使用Unity来解析类型,它将获得必要的依赖项(使用默认生存期注册的新实例),但两者将共享相同的上下文(假设每个都通过构造函数或属性注入依赖于TheContext类。