#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. В этом случае имена классов не имеют значения, только имена свойств; вы пробовали изменить этот фрагмент кода для поддержки лямбда-выражений, может быть, я что-то пропустил в вашем вопросе, и вы хотите сопоставить свойства с разными именами