ASP.NET сопоставить тип модели с типом хранилища?

#c# #asp.net #entity-framework #repository-pattern #unit-of-work

#c# #asp.net #entity-framework #репозиторий-шаблон #единица работы

Вопрос:

Мне было интересно, возможно ли сопоставить тип модели с типом репозитория с помощью C # / ASP.NET. Как вы видите, я пытаюсь реализовать шаблон репозитория / единицы работы. Пример реализации показан ниже:

 public class UnitOfWork : IDisposable
{
    private SchoolContext context = new SchoolContext();
    private DepartmentRepository departmentRepository;
    private CourseRepository courseRepository;

    public DepartmentRepository DepartmentRepository
    {
        get
        {

            if (this.departmentRepository == null)
            {
                this.departmentRepository = new DepartmentRepository(context);
            }
            return departmentRepository;
        }
    }

    public CourseRepository CourseRepository
    {
        get
        {

            if (this.courseRepository == null)
            {
                this.courseRepository = new CourseRepository(context);
            }
            return courseRepository;
        }
    }
  

Однако проблема заключается в том, что UnitOfWork должен сохранять длинный список свойств для каждого типа репозитория. В этом примере это не так уж плохо, поскольку существует только два типа сущностей (отдел, курс) с двумя соответствующими репозиториями (репозиторий department и репозиторий course). Но по мере роста размера приложения класс UnitOfWork быстро становится большим и беспорядочным с десятками или даже сотнями свойств, это будет не что иное, как класс god .

Мне бы хотелось чего-то более общего, например, универсального метода GetRepository(), который сопоставляет тип модели с объектом репозитория. Приведенный ниже псевдокод демонстрирует, что я хочу:

 // definition
public TRepository GetRepository<TModel>(){ // pending implementation } 

// use-case
var departmentRepository = UnitOfWork.GetRepository<TModel>();
  

Итак, как я могу написать такой код, который сопоставляет тип модели с объектом репозитория? Я боюсь, что AutoMapper не будет работать, поскольку он сопоставляет только конкретные реализации, а не общие типы. Что вы думаете? Как вы будете подходить к этой проблеме, когда условие не состоит в том, чтобы жестко кодировать каждую реализацию репозитория как свойства в единице работы?

Комментарии:

1. Удалите репозитории из UnitOfWork. Внедрите UoW в репозитории и получите наборы сущностей из контекста.

2. Немного похоже на задание для внедрения зависимостей и инверсии управления. Вы должны зарегистрировать все модели и соответствующие ассоциации репозиториев в своем загрузчике IOC…

3. Вы можете написать свой собственный mapper для решения этой проблемы

4. @H.Герцль: Я знаю, что могу, но я не знаю как. Если бы я это сделал, я бы не задал этот вопрос.

5. Я добавил asnwer, пожалуйста, проверьте его и дайте мне знать ваши отзывы.

Ответ №1:

Вы можете определить метод расширения следующим образом:

 public static class Mapper
{
    public static T Map<T>(Object source) where T : class
    {
        var instance = Activator.CreateInstance<T>();

        foreach (var property in typeof(T).GetProperties())
        {
            if (property.CanRead)
            {
                var sourceProperty = source.GetType().GetProperty(property.Name);

                if (sourceProperty == null)
                {
                    continue;
                }

                var value = sourceProperty.GetValue(source);

                property.SetValue(instance, value);
            }
        }

        return instance;
    }
}
  

Если вы хотите сопоставить один класс с другим:

 var foo = Mapper.Map<CustomerViewModel>(new Customer { CustomerID = "ACME", CompanyName = "Acme Corp.", ContactName = "Jhon Doe" });
  

Вывод:

{CustomerViewModel} Название компании: «Acme Corp.» Идентификатор пользователя: «ACME»

Предполагая, что у вас есть следующие классы:

 public class Customer
{
    public String CustomerID { get; set; }

    public String CompanyName { get; set; }

    public String ContactName { get; set; }
}

public class CustomerViewModel
{
    public String CustomerID { get; set; }

    public String CompanyName { get; set; }
}
  

Кроме того, это основная идея, вы можете улучшить этот метод расширения для сопоставления из динамического объекта (ExpandoObject), словаря (Dictionary<String, Object>) и создать таблицу сопоставления для повышения производительности при сопоставлении коллекции (большие коллекции элементов).

Этот метод также поддерживает анонимные объекты.

Пожалуйста, дайте мне знать, если этот ответ полезен, мы можем улучшить алгоритм в соответствии с вашими требованиями.

Комментарии:

1. Ну, я уже знаю, как сопоставить модель предметной области с моделью представления, просто используйте automapper, и это работает. У меня вопрос в том, как сопоставить два объекта с несвязанными свойствами / композициями, но с аналогичным соглашением об именах. Допустим, у меня есть модель домена с именем ‘UserModel’, а ее репозиторий называется ‘UserRepository’, я хочу сопоставить ‘UserModel’ с ‘UserRepository’. Как я могу этого добиться?

2. В этом случае имена классов не имеют значения, только имена свойств; вы пробовали изменить этот фрагмент кода для поддержки лямбда-выражений, может быть, я что-то пропустил в вашем вопросе, и вы хотите сопоставить свойства с разными именами