Помогите разобраться с паттерном Репозиторий
В своем пет-проекте не могу понять как лучше поступить с репоизторием. Проект состоит из нескольких микросервисов, каждый в свою очередь использует универсальный дженерик репозиторий:
public class Repository<TEntity, TKey> : IEFRepository<TEntity, TKey>
where TEntity : class where TKey : notnull
Понимаю что нарушаю принципы чистой архитектуры, т.к. детали специфичные для EFCore "вспплывают" на уровень бизнес-логики. Например в IEFRepository<TEntity, TKey> есть такой метод:
public async Task<TEntity?> GetFirstOrDefaultAsync(
Expression<Func<TEntity, bool>>? filter = null,
Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>>? include = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>? orderBy = null,
bool asNoTraсking = true,
CancellationToken ct = default)
Отсюда планирую создать отдельные доменные интерфейсы для каждого микросервиса по типу IUserRepository и свою реализацию, при чем, при создании конретного репозитория хочу просто отнаследоваться от своего общего дженерик репозитория (именно от класса), чтобы работать внутри с его методами, а во вне пойдут методы из доменного интерфейса. Такой подход адекватен? Или наследование от общего репозитория это лишнее?
И дополнительный вопрос, насчет того как лучше работать с отслеживанием сущностей? создавать отдельные методы с трэкингом по типу:
Task<User?> GetByIdWithTrackingAsync(Guid id, CancellationToken ct);
или
Task<User?> GetByIdForUpdateAsync(Guid id, CancellationToken ct);
Затем соответсвенно изменять сущность и вызывать Update() или SaveChanges()?
Также можно всегда возвращать сущности без отслеживания и апдейтить их через ExecuteUpdateAsync(), но не уверен, что такой подход корректен. С другой стороны работа с отслеживаемыми сущностями это особенность именно EFCore, если я, например, захочу перейти на Dapper, то там уже все будет иначе.