Подтвердить что ты не робот

Как использовать интерфейс репозитория, который использует Generics с Injection Dependency Injection?

Я пытаюсь использовать следующий общий интерфейс репозитория для DI и инсталляции конструктора:

public interface IRepository<TEntity> : IDisposable where TEntity : class

Проблема заключается в том, чтобы определить экземпляр интерфейса, я должен предоставить тип класса следующим образом:

private IRepository<Person> _personRepository;

Проблема с этим заключается в том, что я использую DI (и я использую Unity для инфраструктуры IoC), тогда мне нужно определить несколько экземпляров в моем конструкторе, чтобы получить все интерфейсы репозитория, с которыми мне нужно работать следующим образом:

public MyClass(IRepository<Person> personRepository,
               IRepository<Orders> ordersRepository,
               IRepository<Items> itemsRepository,
               IRepository<Locations> locationsRepository)
{
  _personRepository = personRepository;
  _OrdersRepository = ordersRepository; 
  _itemsRepository = itemsRepository;
  _locationsRepository = locationsRepository;
}

Вопросы:

  • Это нормально?
  • Если нет, где я потерял эту концепцию?
  • Даже если это правильно, какой смысл Unity регистрировать Interface для конкретного типа? Я уже сделал это, потому что общий репозиторий заставил меня объявить.

Пожалуйста, помогите мне разобраться, и я ценю всю вашу помощь!

4b9b3361

Ответ 1

Это нормально?

Конечно. Там личное предпочтение от того, использовать ли инъекцию конструктора, как у вас, или вложение собственности. Инъекция конструктора более чистая, поскольку вам не нужно иметь много параметров для вашего конструктора, но это также безопаснее.

какая точка Unity регистрирует интерфейс для конкретного типа

Одна из причин заключается в том, что вы можете unit test MyClass не использовать фактический репозиторий, который попадает в базу данных. Вы можете "подделать" репозиторий для возврата жестко заданных значений для тестирования.

Ответ 2

Как отметил Д. Стэнли, зависимость должна быть конкретным интерфейсом. В противном случае, где вы собираетесь объявить T? Ваш зависимый класс может быть общим, но в какой-то момент вам все равно нужно сказать "T - это лицо".

Тем не менее, Unity обрабатывает типичные типичные типы.

Скажем, вы реализуете IRepository<T> с общим классом Repository<T>, который обертывает DbSet<T> (или что-то еще).

Затем будут работать следующие регистрации и разрешения (включая впрыскивание в любые конструкторы):

container.RegisterType(typeof(IRepository<>), typeof(Repository<>));

// no specific registration needed for the specific type resolves
container.Resolve(<IRepository<Person>);
container.Resolve(<IRepository<Order>); 

Если вам нужно определенное переопределение типа (говорит, что репозиторий Items является специальным по какой-либо причине, поэтому он имеет полностью реализованный класс ItemRepository), просто зарегистрируйте эту конкретную реализацию после общего:

container.RegisterType<IRepository<Item>, ItemRepository>();

Разрешение IRespository<Item> теперь получит вашу конкретную реализацию.

Для записи, я думаю, это можно сделать только в коде, а не в файлах конфигурации. Кто-то может исправить это предположение.

Ответ 3

Вы можете использовать Aggregate Service, который объединяет несколько других сервисов вместе, но вы также должны внимательно посмотреть, есть ли ваш MyClass пытается сделать слишком много; может иметь значение очень большое количество зависимостей.

Ответ 4

Это выглядит нормально, за исключением одной пропущенной точки; для включения транзакций требуется шаблон UnitOfWork. Без применения шаблона UnitOfWork все репозитории пытаются совершить операции db в разных контекстах.

Ответ 5

Мне нужно было сделать это с помощью файла конфигурации. Это на самом деле довольно легко, но мне потребовалось некоторое время, чтобы понять это.

В этом примере у нас есть интерфейс IRepository<T> и он имеет 2 реализации:

  • OneRepository
  • TwoRepository

Затем мы имеем класс с именем Worker, который зависит от IRepository<One> и IRepository<Two>. Мы просим единство создать для нас экземпляр Worker и выяснить зависимости из файла конфигурации.

Интерфейс и реализация

Все они находятся в пространстве имен ConsoleApplication1 в этом примере.

public class Worker
{
    private readonly IRepository<One> one;
    private readonly IRepository<Two> two;

    public Worker(IRepository<One> one, IRepository<Two> two)
    {
        this.one = one;
        this.two = two;
    }

    public string DoOne()
    {
        return this.one.Add(new One());
    }

    public string DoTwo()
    {
        return this.two.Add(new Two());
    }
}

public interface IRepository<T>
{
    string Add(T t);
}

public class OneRepository : IRepository<One>
{
    public string Add(One t)
    {
        return "One";
    }
}

public class TwoRepository : IRepository<Two>
{
    public string Add(Two t)
    {
        return "Two";
    }
}

public class One { }
public class Two { }

Конфигурация Unity

Обратите внимание, что мы инструктируем единство и сообщаем ему название собрания. Затем мы регистрируем 2 реализации.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <assembly name="ConsoleApplication1" />
    <container>
      <register type="ConsoleApplication1.IRepository[[ConsoleApplication1.One]]" mapTo="ConsoleApplication1.OneRepository" />
      <register type="ConsoleApplication1.IRepository[[ConsoleApplication1.Two]]" mapTo="ConsoleApplication1.TwoRepository" />
    </container>
  </unity>
</configuration>

Применение

Это Корень композиции.

public class Program
{
    static void Main()
    {
        UnityContainer container = new UnityContainer();
        var res = container.LoadConfiguration();
        Worker worker = res.Resolve<Worker>();
        Console.WriteLine(worker.DoOne());
        Console.WriteLine(worker.DoTwo());
        Console.Read();
    }
}

Ожидаемый результат:

One
Two