Unity auto-registered repositories on .net for EF Code first

    Hey. Let's get started.


    1. There is a project with Entity framework (> = code first.
    2. You love IoC but don’t like endless registrations of new entities.
    3. Unity is used as a container (or there is an opportunity to spend 10 minutes dopilivaniya source code for your container).
    4. The prospect of writing the same type of code for some reason scares you.

    So what this article offers. You connect 2 nuget packages, implement a simple IRetrievableEntity interface for your Entity (you can simplify the task by inheriting from the finished Entity class), add 2 registration lines to the code and get the full independence from DBContext and the ability to resolve repositories for each IRetrievableEntity entity with the ability to build object-oriented (typed) queries to these repositories. Just look:
    var employeeRepository = container.Resolve>();
    var employees = employeeRepository.Get(q =>
        q = q.Filter(e => e.EmploymentDate >= new DateTime(2014, 9, 1));
            q = q.Filter(e => !e.Fired);
        q = q.Include(e => e.Department, p => p.Department.Chief)
                .OrderBy(p => p.FirstName);

    How to quickly start using

    You can use repositories without IoC, receiving bonuses of building queries and isolation from the context, but the following example and sources will provide comprehensive information about the most productive and simple application.
    1. Install the Rikrop.Core.Data and Rikrop.Core.Data.Unity packages . The first is into a project with Entity entities, the second is into a project with a database context. For example, I used one project, it turned out the following:

    2. Add the following to your IoC registrations:
    //container.RegisterRepositoryContext(s => new MyDbContext(s), "myConStr");

    RepositoryContext is a wrapper over the DBContext class, respectively, registration takes the generic parameter of the descendant from DBContext. You can register a context with the name of the connection string.
    The RegisterRepositories extension method takes an Assembly input, in which POCO objects that implement IRetrievableEntity are located.

    3. Implement for your POCO IRetrievableEntity. For instance:
    public class Department : Entity, IRetrievableEntity {...}
    public class Employee : DeactivatableEntity, IRetrievableEntity {...}

    4. Done. You can use:
    var departmentRepository = container.Resolve>();
    departmentRepository.Save(new Department { Name = "TestDepartment" });
    var testDeps = departmentRepository.Get(q => q.Filter(dep => dep.Name.Contains("Test")));

    It is impossible to make a mistake, since generic-parameters make sure that the correct repositories are resolved:
    // Разрешить IDeactivatableRepository для департамента нельзя (ошибка компиляции), 
    // т.к. эта сущность не относледована от DeactivatableEntity.
    //var departmentRepository2 = container.Resolve>();

    5. If the standard functionality offered by the IRepository interfacesand IDeactivatableRepositoryfor any entity is not enough, you can always expand an existing implementation in a couple of simple steps. Set the interface:
    public interface IPersonRepository : IDeactivatableRepository
        void ExtensionMethod();

    Add the implementation and be sure to mark it with the attribute:
    public class PersonRepository : DeactivatableRepository, IPersonRepository
        public PersonRepository(IRepositoryContext repositoryContext) 
            : base(repositoryContext)
        public void ExtensionMethod()
            // Здесь у вас будет доступ к DBContext
            Console.WriteLine("PersonRepository ExtensionMethod called");

    We ask Unity to find and register all extended repositories in the given assembly:
    // Пример регистрации "расширенных" репозиториев без указания их типа.

    We use:
    // Извлечение "расширенного" репозитория по интерфейсу.
    var personRepository = container.Resolve();

    Moreover, without the need for advanced methods, you can always use the standard implementation:
    // Для класса Person репозиторий зарегистрирован под обоими интерфейсами, поскольку сущность наследуется от DeactivatableEntity.
    var personRepository2 = container.Resolve>();
    var personRepository3 = container.Resolve>();

    How it works

    There is a basic repository implementation that works with context through the IRepositoryContext abstraction. Accessing the dataset from the repository works thanks to the DBContext generic methods:
    public override DbSet Data { get { return Context.Set(); } }

    The key class for working with building queries to the repository is the RepositoryQuery class . The class implements a fluent interface and allows you to do Include by Expression or by a text path (the latter can be relevant when loading properties of child collections, when the path cannot be specified through expression), filter, sort, Skip and Take.
    The magic of registration is based on Reflection. When registering repositories in the assembly, all classes inherited from IRetrievableEntity <,> are found, generic arguments are taken from them, new types IRepository <,> and Repository <,> are built with the necessary generic arguments, then all this is registered using types freshly created through reflection . For extended repositories, the search is performed by the attribute:
    foreach (var repositoryType in assembly.GetTypes().Where(type => type.IsClass))
        var repositoryAttribute = repositoryType.GetCustomAttribute();
        if (repositoryAttribute != null)
                            repositoryType, new TransientLifetimeManager());


    1. Only Entity framework and only Unity. The tool was created for our personal purposes and therefore it is rather difficult to find motivation to implement, for example, registrations for other containers.
    2. The script is suitable for use with a single DBContext - different ones will not be able to resolve the repository. This restriction does not apply to the use of Rikrop.Core.Data without Rikrop.Core.Data.Unity.
    3. Fixed version of Unity. If the version is not explicitly specified in the Nuget package for 4.0, then nuget will try to resolve the latest version, although it is incompatible with .net 4. If anyone knows a way to get rid of this problem, please inform in PM.
    4. Only .net 4.0 and 4.5.


    Also popular now: