Arhn - архитектура программирования

Фабрика репозиториев с Ninject

В своем приложении я использую репозитории для операций CRUD. Из всех сущностей некоторые не должны удаляться вообще, некоторые сущности (которые реализуют ISoftDeletable) можно удалить только обратимо, а некоторые сущности (которые реализуют IPermanentDeletable) могут быть удалены без возможности восстановления. (Я слежу за ответом на этот пост Универсальный репозиторий с функцией мягкого удаления )

У меня есть 3 репозитория, которые наследуются друг от друга следующим образом

BaseRepository : IRepository

SoftDeleteRepository : BaseRepository, ISoftDeleteRepository

PermanentDeleteRepository : BaseRepository, IPermanentDeleteRepository

Моя проблема в том, что я не хочу делать индивидуальную привязку для каждого из объектов разных типов, таких как

kernel.Bind(typeof(IRepository<Company>)).To(typeof(BaseRepository<Company>));
kernel.Bind(typeof(IRepository<Country>)).To(typeof(PermanentDeleteRepository<Country>));
kernel.Bind(typeof(IRepository<Contact>)).To(typeof(SoftDeleteRepository<Contact>));

Но вместо этого я хочу как-то сделать так, чтобы все привязки для IRepository отправлялись на фабрику и создавали экземпляр репозитория в зависимости от типа сущности, которую принял его общий параметр, и внедряли его в контроллер.

Можно ли этого добиться?


Ответы:


1

Итак, вот как вы могли бы добиться этого, все еще внедряя IRepository<XYZ> в потребителя:

public interface ISoftDeletable
{
}

public interface IPermanentDeleteable
{
}

public interface IRepository<TEntity>
{
}

public class PermanentDeletableRepository<TEntity> : IRepository<TEntity>
    where TEntity : IPermanentDeleteable
{
}

public class SoftDeletableRepository<TEntity> : IRepository<TEntity>
    where TEntity : ISoftDeletable
{
}

public class RepositoryModule : NinjectModule
{
    public override void Load()
    {
        this.Bind(typeof(IRepository<>))
            .To(typeof(PermanentDeletableRepository<>))
            .When(IsRequestForRepositoryOfEntityImplementing<IPermanentDeleteable>);

        this.Bind(typeof(IRepository<>))
            .To(typeof(SoftDeletableRepository<>))
            .When(IsRequestForRepositoryOfEntityImplementing<ISoftDeletable>);
    }

    public static bool IsRequestForRepositoryOfEntityImplementing<TInterface>(IRequest request)
    {
        Type entityType = GetEntityTypeOfRepository(request.Service);
        return ImplementsInterface<TInterface>(entityType);
    }

    public static Type GetEntityTypeOfRepository(Type repositoryType)
    {
        // target.Type must be IRepository<"AnyEntity">
        return repositoryType.GetGenericArguments().Single();
    }

    public static bool ImplementsInterface<TInterface>(Type type)
    {
        return typeof(TInterface).IsAssignableFrom(type);
    }
}

Я проверил модульным тестом, что он работает:

    public class SomeSoftDeletableEntity : ISoftDeletable
    {
    }

    [Fact]
    public void RepositoryBinding()
    {
        var kernel = new StandardKernel();
        kernel.Load<RepositoryModule>();

        IRepository<SomeSoftDeletableEntity> repository = kernel.Get<IRepository<SomeSoftDeletableEntity>>();

        repository.Should().BeOfType<SoftDeletableRepository<SomeSoftDeletableEntity>>();
    }
11.03.2014
  • относительно public override void Load(). что, если у меня есть и другие типы репозиториев? Например, любой объект, который не реализует ни ISoftDeletable, ни IPermanentDeletable, должен использовать BaseRepository. Достаточно ли для этого вызвать base.Load() в первую очередь в методе Load, который мы переопределяем? 11.03.2014
  • Извините, код, который я разместил, несколько неполный. Метод Load должен быть частью Module : NinjectModule, который затем загружается IKernel.Load<Module>(). Вы также можете создать привязки с помощью IKernel.Bind(...) - это не имеет значения. На ваш вопрос о других объектах: вы должны создать третью привязку, привязку по умолчанию: IBindingRoot.Bind(typeof(IRepository<>)).To(typeof(BaseRepository<>));. Когда есть несколько привязок, ninject будет использовать одну с .When(...), прежде чем использовать другую без. 11.03.2014
  • Большое вам спасибо за вашу помощь. Он работает так, как я хотел. 11.03.2014
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..