Ця стаття має кілька недоліків. Будь ласка, допоможіть удосконалити її або обговоріть ці проблеми на сторінці обговорення.
Ця стаття не має інтервікі-посилань. Ви можете допомогти проєкту, знайшовши та додавши їх до відповідного елементу Вікіданих.(15 червня 2019)
Ця стаття містить перелік посилань, але походження тверджень у ній залишається незрозумілим через практично повну відсутність внутрішньотекстових джерел-виносок. Будь ласка, допоможіть поліпшити цю статтю, перетворивши джерела з переліку посилань на джерела-виноски у самому тексті статті.(15 червня 2019)
Вступний розділ цієї статті, ймовірно, несповна підсумовує ключові тези її вмісту. Будь ласка, допоможіть розширити вступ, додавши стислий огляд найважливіших аспектів статті.(15 червня 2019)
Repository — патерн, який розділяє рівні джерела даних і логіки програми. Часто використовується із патерном Unit Of Work
Зміст
1Переваги та недоліки
1.1Переваги
1.2Недоліки
2Опис мовою C#
3Зв'язок з іншими патернами
4Реалізація
5Див. також
6Джерела
Переваги та недоліки
Цей розділ має вигляд переліку, який краще подати прозою. Ви можете допомогти викласти список прозою, де це доречно. Ознайомтеся з довідкою з редагування.(15 червня 2019)
Переваги
Використовується, як колекція
Інкапсулює великі запити до БД в методи
Рівень абстракції між Business Logic рівнем та Data Access рівнем
Ізолює програму від змін джерела даних
Джерело даних може бути змінено без будь-яких змін в бізнес логіці і з мінімальними змінами в Репозиторії
Полегшує автоматизоване юніт тестування, Test Driven Development
Легко створювати mock репозиторію
Недоліки
Зростає кількість класів
Погіршує продуктивність
Обмежує у використанні особливостей ОРМ фреймворку
Опис мовою C#
Використаємо Entity Framework. Нехай дано клас-сутність User
Тепер напишемо інтерфейс репозиторію. Варто зазначити, що репозиторій є колекцією, і має поводитись як колекція, та не містити методів Update(), Save() тощо. Також однією із великих помилок, є те що методи повертають IQueryable замість IEnumerable. Якщо повертати IQueryable це дозволить надбудувати над запитом, ще запити, що не є вірним, оскільки мета цього патерну якраз і є уникнення великих запитів. В такому разі, краще написати ще один метод, який буде виконувати більший запит.
Тепер реалізуємо цей інтерфейс у вигляді узагальненого класу. При реалізації ми повертаємо сутність, а не DTO. Мапування — це не відповідальність репозиторію.
publicclassGenericRepository<TEntity>:IRepository<TEntity>whereTEntity:class{// FIELDS// узагальнений контекстprotectedDbContextdbContext;protectedDbSet<TEntity>dbSet;// CONSTRUCTORSpublicGenericRepository(DbContextdbContext){this.dbContext=dbContext;this.dbSet=dbContext.Set<TEntity>();}// METHODSpublicvirtualintCount(){returndbSet.Count();}publicvirtualintCount(Expression<Func<TEntity,bool>>predicate){returndbSet.Count(predicate);}publicvirtualIEnumerable<TEntity>Get(Expression<Func<TEntity,bool>>filter=null,Func<IQueryable<TEntity>,IOrderedQueryable<TEntity>>orderBy=null,stringincludeProperties="",int?page=null,int?amount=null){// filterIQueryable<TEntity>query=dbSet;if(filter!=null){query=query.Where(filter);}// include propertiesforeach(stringincludePropertyinincludeProperties.Split(newchar[]{',',' '},StringSplitOptions.RemoveEmptyEntries)){query=query.Include(includeProperty);}// orderingif(orderBy!=null)query=orderBy(query);// pagingif(page.HasValue&&amount.HasValue)query=query.Skip((page.Value-1)*amount.Value).Take(amount.Value);returnquery;}publicvirtualTEntityGet(intid){returndbSet.Find(id);}publicvirtualvoidInsert(TEntityentity){dbSet.Add(entity);}publicvirtualvoidDelete(objectid){// findif(id==null)thrownewArgumentNullException(nameof(id));TEntityentityToDelete=dbSet.Find(id);// delete findedif(entityToDelete==null)thrownewInvalidOperationException("There is no records with such id");Delete(entityToDelete);}publicvirtualvoidDelete(TEntityentityToDelete){if(entityToDelete==null)thrownewArgumentNullException(nameof(entityToDelete));if(dbContext.Entry(entityToDelete).State==EntityState.Detached){dbSet.Attach(entityToDelete);}dbSet.Remove(entityToDelete);}publicvirtualvoidDelete(Expression<Func<TEntity,bool>>predicate){if(predicate!=null)dbSet.RemoveRange(dbSet.Where(predicate));elsedbSet.RemoveRange(dbSet);}}
Тепер залишилось для кожної сутності реалізувати свій репозиторій. Напишемо інтерфейс, який додаватиме (а можливо і ні) новий функціонал для конкретного репозиторію.
Поле первинного ключа (Identity Field) • Розмітка зовнішніх ключів (Foreign Key Mapping) • Розмітка зв'язків таблиць (Association Table Mapping) • Відображення залежних об'єктів (Dependent Mapping) • Об'єднане значення (Embedded Value) • Серіалізований великий об'єкт (Serialized LOB) • Наслідування з однією таблицею (Single Table Inheritance) • Наслідування з таблицею для кожного класу (Class Table Inheritance) • Наслідування з таблицею для кожного конкретного класу (Concrete Table Inheritance) • Відображення із наслідуванням (Inheritance Mappers) • База даних звітності
Шаблони обробки об'єктно-реляційних метаданих
Відображення на основі метаданих (Metadata Mapping) • Об'єкт-запит (Query Object) • Сховище (Repository)
Збереження стану сеансу на стороні клієнта (Client Session State) • Збереження стану сеансу на стороні сервера (Server Session State) • Збереження стану сеансу в базі даних (Database Session State)