开发者

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

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?


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜