C#/EF and the Repository Pattern: Where to put the ObjectContext in a solution with multiple repositories?

自作多情 提交于 2019-12-28 12:44:06

问题


I have multiple repositories in my application. Where should I put the ObjectContext? Right now, I have a reference like ObjectContext ctx; in every repository. What is the smartest and safest way to go about this?


回答1:


A design with multiple ObjectContext instances is only acceptable if your Repository methods commit the transaction. Otherwise, it is possible that external calls to commit the transaction may not persist everything you intend, because you will hold references to different instances of the ObjectContext.

If you want to restrict the ObjectContext to a single instance, then you can build a RepositoryProvider class that contains the ObjectContext, and manages the propagation of repository actions to data commits. This can be best accomplished by either, - Injecting the ObjectContext reference into each repository, or - Subscribing the repositories' events to EventHandlers that call the appropriate methods on the ObjectContext.

The following is a highly pluggable implementation that I have used:

Repository Provider Interface

public interface IRepositoryProvider
{
    IRepository this[Type repositoryType] { get; }
}

Repository Factory Interface

The implementation has dependency on an IEnumerable<IFilteredRepositoryFactory>.

public interface IFilteredRepositoryFactory{
   bool CanCreateRepository(Type repositoryType);
   IRepository CreateRepository(Type repositoryType, ObjectContext context);
}

So, the implementation looks like:

Repository Provider Class

public class RepositoryProvider
{
    public RepositoryProvider(ObjectContext context, IEnumerable<IFilteredRepositoryFactory> repositoryFactories)
    {
        _context = context;
        _repositoryFactories = repositoryFactories;
    }

    private readonly ObjectContext _context;
    private readonly IEnumerable<IFilteredRepositoryFactory> _repositoryFactories;
    private readonly Dictionary<Type, IRepository> _loadedRepositories;

    IRepository this[Type repositoryType]
    {
        get
        {
            if(_loadedRepositories.ContainsKey(repositoryType))
            {
                return _loadedRepositories[repositoryType];
            }
            var repository = GetFactory(repositoryType).CreateRepository(repositoryType, _context);
            _loadedRepositories.Add(repositoryType,repository);
            return repository;
        }
    }

    IFilteredRepositoryFactory GetFactory(Type repositoryType)
    {
        //throws an exception if no repository factory is found
        return _repositoryFactories.First(x => x.CanCreateRepository(repositoryType));
    }
}

It should be noted that a new Repository will be created by the first matching factory implementation. So, if the collection of factories contains multiple factories that can create a Repository for the given repository Type, the first IFilteredRepositoryFactory object in the enumerable will be used and any subsequent factories will be ignored. In addition, if there is no registered factory, and exception will be thrown.




回答2:


What I Normally do is create a ObjectContext once and store it in Thread Local Storage (using NamedThreadDataSlot) and access the ObjectContext from there. This ensures that the ObjectContext is shared across the request, which will be handled by one thread.



来源:https://stackoverflow.com/questions/5032810/c-ef-and-the-repository-pattern-where-to-put-the-objectcontext-in-a-solution-w

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!