【问题标题】:Generic repository lifetime configuration with WindsorWindsor 的通用存储库生命周期配置
【发布时间】:2011-04-20 06:57:38
【问题描述】:

我不知道如何配置正确的 Windsor 容器以与 Windows 应用程序中的存储库一起使用。 我有通用存储库实现Repository,其中T是实体类型,它有一个依赖IDatacontextProvider,它为其提供数据上下文:

public class Repository<T> : IRepository<T> where T : class
{
    protected DataContext DataContext;
    public Repository(IDataContextProvider dataContextProvider) {
         DataContext = dataContextProvider.DataContext;
    }
    ....
}

对于简单的事情,以下配置一切正常:

 container.Register(                                
            Component.For<IDataContextProvider>()
                  .ImplementedBy<DataContextProvider>()
                  .Lifestyle.Transient,
            Component.For(typeof(IRepository<>))
                  .ImplementedBy(typeof(Repository<>))
                  .Lifestyle.Transient, .... 

当我尝试加入来自多个存储库的不同实体时,只要每个存储库实例具有不同的数据上下文实例,就会出现问题。
例如我有简单的服务:

public class SimpleService : ISimpleService {
     public SimpleService(IRepository<Order>, IRepository<OrderLine>) {
         ....
     }
}

我可以将 IDataContextProvider 设为 Singleton,但我认为这会带来更大的问题。
我可以将 IDataContextProvider 传递给 SimpleService,并尝试在那里解析存储库实例,但这需要额外的代码来使服务易于测试,并且需要额外的依赖项。 可能有人对如何解决这个问题有更好的想法?

更新: 根据建议,我创建了存储库工厂(它与答案中提出的有点不同,它不直接依赖于数据上下文,但想法非常相同):

 public interface IRepositoryFactory
{
    IRepository<T> GetRepository<T>() where T:class;
}

public class RepositoryFactory : IRepositoryFactory
{
    private readonly IDataContextProvider dataContextProvider;

    public RepositoryFactory(IDataContextProvider dataContextProvider)
    {
        this.dataContextProvider = dataContextProvider;
    }

    public IRepository<T> GetRepository<T>() where T : class
    {
        return new Repository<T>(dataContextProvider);
    }
}

【问题讨论】:

  • 为什么单例会导致“更大”的问题?对于只有一个线程的 Windows 应用程序,这应该是最好的选择..
  • 好吧,因为 DataContext 并不意味着长寿(它没有缓存清除、多次提交的更改分离等 - 它假设您将释放它并尽快创建新实例可能),对此有很多讨论(例如:stackoverflow.com/questions/226127/…)。此外,还有多个用户,并且在很多地方都使用了线程。
  • 好的,我明白了。对Entity Framework不太熟悉,自己用NHibernate。为什么没有一个 RepositoryFactory,它需要一个 IDataContextProvider。您的用户类可以将 IRepositoryFactory 作为依赖项,并从那里获取他们需要的存储库,并且从 RepositoryFactory 的同一实例创建的所有存储库将共享相同的 DataContext。
  • 非常有趣的想法,我会尝试看看它在代码中的样子。
  • 我添加了一个可能的解决方案的答案。

标签: c# winforms castle-windsor ioc-container


【解决方案1】:

如果中间有另一个层,比如 RepositoryFactory?那个人可能有一种短暂的生活方式。从工厂创建的所有存储库将共享相同的 DataContext 实例。您还需要更改存储库类,以便它们采用 DataContext 实例而不是 DataContextProvider。

public class RepositoryFactory : IRepositoryFactory
{
   protected DataContext dataContext;
   public RepositoryFactory(IDataContextProvider provider)
   {
      dataContext = dataContextProvider.DataContext;
   }

   public IRepository<T> GetRepository<T>()
   {
      return new Repository<T>(dataContext);
   }
}

public class SimpleService : ISimpleService {
     public SimpleService(IRepositoryFactory factory) {
         ....
     }
}

【讨论】:

  • 好吧,我在我的问题中提到,这是 Windows 应用程序,所以 PerWebRequest 不适用于这种情况。我已经在具有相同存储库实现的 Web 应用程序中使用了它,但效果很好。
【解决方案2】:

IDatacontextProvider 听起来像一个工厂接口,这些通常在依赖注入中定义为单例。我看到了几种可能的解决方案:

  1. 我不知道你的申请细节,但也许你可以为IDatacontextProvider编写你自己的生活方式管理器(因为你说单身和临时都不适合你)。
  2. 如果您想确保在存储库之间传递相同的 IDatacontextProvider,也许您应该考虑将其显式提供为方法参数,而不是注入依赖项。
  3. @Can 的回答也是一个可能的解决方案,我自己用过一次。

【讨论】:

  • 关于自己的生活方式,有blog.schuager.com/2010/11/contextual-lifestyle-reloaded.html,看起来也很有趣,也很干净。
  • @Giedrius,这个链接也很有趣,但我不喜欢你需要引用内核才能创建 ContainerContext。这意味着将创建上下文的客户端类需要了解城堡内核..
  • @Can,好吧,我也不喜欢这样,但从另一方面来说,它可能有助于解决更复杂的组合问题,比如 serviceA 使用 serviceB 并且都使用 repositoryC 和 repositoryD,这需要来具有相同的数据上下文。
【解决方案3】:

您的问题在于生活方式的配置。我有同样的问题。您必须使用 PerWebRequest 生活方式配置您的存储库。这给了我很好的性能提升,并将我的错误从几十个减少到零。

在我的博客上你可以找到一个简单的例子http://marcofranssen.nl 依赖注入结合 mvc3 和 EF 代码优先。

【讨论】:

  • 有人提到,我说的是windows app,而不是web app。
  • 我知道,但您可以将此示例翻译到您的 Windows 应用程序中。该示例在 web 应用中,但您可以对 Windows 应用执行相同操作。
  • 事情是,在 Windows 窗体中通常一切都更复杂 - 很难将工作流拆分为“请求”。例如,如果打开子窗口,我应该将其视为新请求吗?如果是,那么通过网络定义,应该处理父窗口请求吗?如果不是,那么新的请求是什么?我并不是说这个想法不有趣,只是目前不知道它会是什么样子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 2017-12-21
  • 1970-01-01
  • 2019-06-19
  • 2014-07-18
  • 1970-01-01
相关资源
最近更新 更多