У меня проблема с реализацией универсального контроллера для операций CRUD с моими сущностями.
В настоящее время у меня есть следующие классы:
public class BaseItem
{
public int? Id { get; set; }
}
Этот класс является родительским для нескольких сущностей:
public class Customer : BaseItem
{
// some fields
}
public class Project : BaseItem
{
// some fields
}
Затем есть интерфейс для универсального репозитория:
public interface IGenericItemRepository<TDomain>
where TDomain : BaseItem
{
// methods
}
И на основе этого интерфейса строятся более конкретные интерфейсы:
public interface ICustomerRepository : IGenericItemRepository<Customer> {}
Чтобы сейчас не решать EF, я использую mock-классы. Делаются они следующим образом:
public abstract class GenericMockRepository<TDomain> : IGenericItemRepository<TDomain> where TDomain : BaseItem
...
и реализует всю логику базового CRUD. Конкретный фиктивный репозиторий делается следующим образом:
public class MockCustomerRepository : GenericMockRepository<Customer>, ICustomerRepository
{
public MockCustomerRepository() : base()
{
CreateCustomersList();
}
private void CreateCustomersList()
{
// method body
}
}
Итак, в целом я мог бы использовать мою существующую настройку для реализации контроллера следующим образом:
public class CustomersController : Controller
{
private ICustomerRepository _customerRepo;
public CustomersController(ICustomerRepository customerRepo)
{
_customerRepo = customerRepo;
}
}
Затем я попытался реализовать универсальный контроллер:
public interface IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>
where TDomain : BaseItem
where TDetailsViewModel : BaseViewModel, new()
where TEditViewModel : BaseViewModel, new()
where TRepo : IGenericItemRepository<BaseItem>
{
[HttpGet] public IActionResult Edit(int? id);
[HttpPost] public IActionResult Edit(TDomain entity);
[HttpGet] public IActionResult Details(int? id);
}
public class BaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo> : Controller, IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>
where TDomain : BaseItem
where TDetailsViewModel : BaseViewModel, new()
where TEditViewModel : BaseViewModel, new()
where TRepo : IGenericItemRepository<BaseItem>
{
private IGenericItemRepository<BaseItem> _repo;
public BaseController(IGenericItemRepository<BaseItem> repo)
{
_repo = repo;
}
}
Но когда я пытаюсь изменить свой CustomerController на этот код ниже:
public class CustomersController : BaseController<Customer, BaseViewModel, BaseViewModel, ICustomerRepository>
{
private ICustomerRepository _customerRepo;
public CustomersController(ICustomerRepository customerRepo)
{
_customerRepo = customerRepo;
}
}
есть следующая ошибка:
Ошибка CS0311 Тип «DAL.Repositories.ICustomerRepository» не может быть используется как параметр типа «TRepo» в универсальном типе или методе 'BaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>'. Нет неявного преобразования ссылок из «DAL.Repositories.ICustomerRepository» в 'DAL.Repositories.IGenericItemRepository<Domain.BaseItem>'.
Но мой ICustomerRepository
типа IGenericItemRepository
, не так ли?
Как я могу исправить ошибку и правильно реализовать универсальный контроллер, чтобы я мог повторно использовать его в своих конкретных контроллерах? Я проверял похожие темы, но поскольку общий репозиторий реализован иначе, чем у меня, я не мог исправить это на основе примеров... Причина, по которой у меня есть дополнительные интерфейсы для конкретных репозиториев, заключается в том, что для каждого типа сущности будет быть более конкретными методами, поэтому я хотел бы определить их в конкретных интерфейсах (поэтому у меня нет чего-то вроде
public interface IBaseRepository
{
T Get<T>(int id);
void Save<T>(T entity);
}
Большое спасибо за любую помощь заранее!
Попробуйте IGenericItemRepository<TDomain>
вместо IGenericItemRepository<BaseItem>
в своих BaseController
и IBaseController
.
public class BaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo> : Controller, IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>
where TDomain : BaseItem
where TDetailsViewModel : BaseViewModel, new()
where TEditViewModel : BaseViewModel, new()
where TRepo : IGenericItemRepository<TDomain>
{
private IGenericItemRepository<TDomain> _repo;
public BaseController(IGenericItemRepository<TDomain> repo)
{
_repo = repo;
}
}
public interface IBaseController<TDomain, TDetailsViewModel, TEditViewModel, TRepo>
where TDomain : BaseItem
where TDetailsViewModel : BaseViewModel, new()
where TEditViewModel : BaseViewModel, new()
where TRepo : IGenericItemRepository<TDomain>
{
[HttpGet] public IActionResult Edit(int? id);
[HttpPost] public IActionResult Edit(TDomain entity);
[HttpGet] public IActionResult Details(int? id);
}
Но мой
ICustomerRepository
типаIGenericItemRepository
, не так ли? нет, посмотрите на Ковариантность и контравариантность в дженериках