Хранилище - это абстракция, которая представляет любое базовое и произвольное хранилище данных, как если бы это была коллекция объектов в памяти.
Это определение трансформируется в более практичную форму из-за общепринятых практик и системных ограничений: набор объектов в памяти, которые представляют некоторое базовое и произвольное хранилище данных, возможно, отключенное . Внутри хранилища можно связать базу данных, плоский файл, коллекцию объектов в памяти или все, что вы можете себе представить. Пользователю хранилища все равно.
Таким образом, IRepository
- это интерфейсный контракт, который определяет, как код Api желает, чтобы код клиента взаимодействовал с хранилищем. Это часто включает в себя добавление, обновление, удаление и получение контрактов, как, например, этот очень распространенный пример контракта с репозиторием:
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> GetAll();
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
Но я предпочитаю использовать другой интерфейс по нескольким причинам.
Во-первых, вы обычно не будете использовать репозиторий сам по себе, вы, вероятно, будете использовать его с шаблоном единицы работы, поэтому в репозитории не должно быть метода Save (). У него может быть Update(T entity)
метод - но почему? Объект, который вы получаете из репозитория, будет автоматически обновляться / обновляться так же, как любой другой объект, который вы получили бы из любого вида коллекции объектов, потому что вы получили ссылки на сами объекты. (Например: если ваш TEntity
является Person
объектом, и вы получаете человека "Чак", и вы изменяете его фамилию с "Bartowski" на "Carmichael", хранилище, по-видимому, уже обновило указанную сущность. Если это кажется ненадежным, в реализации метода Update(T entity)
нет ничего плохого.)
Во-вторых, большинство репозиториев должно быть в состоянии обрабатывать отключенные среды. Если ваше решение не имеет этого требования, вы все равно можете создать интерфейс, который обрабатывает отключенные сценарии и просто оставить его невыполненным. Теперь вы готовы к будущему.
Наконец, наш контракт имеет больше смысла для истинной природы хранилища - коллекция объектов в памяти, которые представляют собой произвольное хранилище данных, возможно, отключенное .
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> GetAll();
List<TEntity> Get(Func<TEntity, bool> where);
void Insert(TEntity entity);
void Insert(IEnumerable<TEntity> entities);
void Remove(TEntity entity);
void Remove(IEnumerable<TEntity> entities);
void SyncDisconnected(TEntity entity, bool forDeletion = false);
void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}
Если вы определили базовый класс для всех ваших сущностей, назовем его DomainObject
, и вы дадите ему поле Id
, тогда вы можете сделать следующее:
public interface IRepository<TEntity> where TEntity : DomainObject
{
TEntity GetById(object Id);
List<TEntity> GetAll();
List<TEntity> Get(Func<TEntity, bool> where);
void Insert(TEntity entity);
void Insert(IEnumerable<TEntity> entities);
void Remove(TEntity entity);
void Remove(IEnumerable<TEntity> entities);
void SyncDisconnected(TEntity entity, bool forDeletion = false);
void SyncDisconnected(IEnumerable<TEntity> entities, bool forDeletion = false);
}
Если вам не нравится необязательный параметр forDeletion
, вы можете добавить метод, который также позволяет синхронизировать удаленные объекты:
void SyncDisconnectedForDeletion(TEntity entity);
Причина, по которой вам нужно это сделать, заключается в том, что в большинстве случаев синхронизация отключенных объектов для удаления несовместима с синхронизацией отключенных объектов для добавления или изменения. (Попробуйте. Вы сами увидите, что требования для удаления в магазине сильно отличаются от требований добавления или изменения). Следовательно, интерфейс должен определять контракт, чтобы реализация могла различаться между ними.
Этот интерфейс можно реализовать для ЛЮБОГО репозитория ЛЮБОГО базового хранилища данных, подключенного или отключенного, включая другие абстракции к базовым хранилищам данных, например Entity Framework.