Generic repository lifetime configuration with Win

2019-05-23 07:14发布

I'm out of ideas how to configure right Windsor container for use with repositories in Windows app. I have generic repository implementation Repository, where T is entity type, it has a dependency IDatacontextProvider, which provides datacontext for it:

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

And for simple things everything works ok with following configuration:

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

Problems occur, when i try to join different entities from several repositories, as long as each repository instance has different data context instance.
For example i have simple service:

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

I could make IDataContextProvider as Singleton, but i think that would bring even bigger problems.
I could pass IDataContextProvider to SimpleService, and try to resolve repository instances there, but that would require additional code to make service easy testable and would require additional dependencies. May be somebody has a better idea how to solve this?

update: following advice, I've created repository factory (it's little bit different from proposed in answer, it does not have direct dependency to datacontext, but idea is very same):

 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);
    }
}

3条回答
SAY GOODBYE
2楼-- · 2019-05-23 07:18

IDatacontextProvider sounds like a factory interface and these are usually defined as singletons in the dependency injection. I see several potential paths to a solution:

  1. I don't know about particulars of your application, but maybe you can write your own lifestyle manager for IDatacontextProvider (since you say neither singleton nor transient suits you).
  2. If you want to ensure the same IDatacontextProvider is passed among repositories, maybe you should think about providing it explicitly as a method parameter, instead of an injected dependency.
  3. @Can's answer is also a possible solution, I've used that one myself once.
查看更多
家丑人穷心不美
3楼-- · 2019-05-23 07:20

Your problem is in the configuration of the lifestyle. I had the same issues. You have to configure your repositories with an PerWebRequest lifestyle. This gave me an nice performance boost and reducing my errors from dozens to zero.

On my blog you can find an simple example http://marcofranssen.nl of dependency injection in combination with mvc3 and EF Code first.

查看更多
闹够了就滚
4楼-- · 2019-05-23 07:24

What about having another layer in between, such as a RepositoryFactory? That one could have a transient lifestyle. All repositories created from the factory would share the same DataContext instance. You would also need to change your repository classes so they take a DataContext instance instead of a 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) {
         ....
     }
}
查看更多
登录 后发表回答