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 EventHandler
s 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.
来源:https://stackoverflow.com/questions/5032810/c-ef-and-the-repository-pattern-where-to-put-the-objectcontext-in-a-solution-w