ORM Паттерны. Repository Repository (хранилище) выступает в роли посредника между слоем домена и слоем отображения данных, предоставляя интерфейс в виде.

Презентация:



Advertisements
Похожие презентации
ПАТТЕРН «SPECIFICATION» Презентацию подготовил студент 245 группы Математико - механического факультета СПбГУ Мусаев Мехти
Advertisements

ДЕЛЕГАТЫ Лекция 7 1. Зачем нужны делегаты 2 И данные, и код располагаются в памяти компьютера по определенным адресам. Передача адресов данных в C# происходит.
Технология ORM и её реализации. Что такое ORM? ORM (Object-relational mapping) технология программирования, которая связывает базы данных с концепциями.
Перегрузка операторов x = a + b результат 1-й операнд2-й операнд оператор По количеству операндов операторы делятся на: унарные (один операнд) бинарные.
ИТЕРАТОРЫ И LINQ Лекция 1. Интерфейс IEnumerable и IEnumerator Любая коллекция реализует интерфейс IEnumerable. public interface IEnumerable : IEnumerable.
Высокоуровневые методы информатики и программирования Лекция 14 Интерфейсы.
АССОЦИАТИВНЫЕ КОЛЛЕКЦИИ Лекция 6 1. Отличие от последовательных 2 В последовательной коллекции каждый элемент ассоциируется с номером, начиная с 0. В.
NHibernate что, где, когда Артур Дробинский ЗетаСофт Томск, 2012.
Наследование Наследование – это отношение является между классами. class Person { string first_name; int birth_year;... } class Student : Person { float.
С# и ООП Формальное определение класса с C# Класс в C# - это пользовательский тип данных (user defined type), который состоит из данных (часто называемых.
Учебный курс Объектно-ориентированный анализ и программирование Лекция 7 Методы как средство реализации операций Лекции читает кандидат технических наук.
Делегаты Как созданные объекты могут посылать сообщения тем объектам, которые их породили? При программировании под Windows на С и C++ основное средство.
Создание клонируемых объектов (интерфейс IClonable)
Коллекции Во многих приложениях требуется создавать группы связанных объектов и управлять этими группами. Существует два способа группировки объектов:
В С# предусмотрены средства для создания пользовательских классов-контейнеров, к внутренним элементам которых можно обращаться при помощи того же оператора.
Интерфейсы Интерфейс представляет собой полностью абстрактный класс, все методы которого абстрактны. Методы интерфейса имеют модификаторы public и abstract,
Внедрение зависимостей. IoC-контейнеры Лекция 03.
Классы WindowsForms элементов управления для работы со структурами данных Control ListViewTreeViewListControl ComboBoxListBox CheckedListBox DataGridViewDataGrid.
EXtreme Programming XP Тема 3. XP Пусть есть некоторая информационная система для банков. В качестве основной валюты для расчетов используется доллар,
САОД кафедра ОСУ 1 Основные абстрактные типы данных Схема процесса создания программ для решения прикладных задач ВУ.
Транксрипт:

ORM Паттерны

Repository Repository (хранилище) выступает в роли посредника между слоем домена и слоем отображения данных, предоставляя интерфейс в виде коллекции для доступа к объектам домена.

Пример Обратимся к упомянутому ранее примеру на NHibernate. Пусть у нас определн класс автора: public class Author { public virtual int Id { get; set; } public virtual string FirstName { get; set; } public virtual string LastName { get; set; } public virtual int YearOfBirth { get; set; } public virtual Iesi.Collections.Generic.ISet Books { get; set; } }

Пример Файл, который отображает класс автора на таблицу БД:

Пример Пусть нам необходимо заполнить выпадающий список именами авторов, скажем, для того чтобы впоследствии вывести список всех его работ: public void FillAuthorsComboBox(ComboBox comboBox, ISessionFactory factory) { ISession session = factory.OpenSession(); try { IQuery authorsQuery = session.CreateQuery("FROM Author"); IList authors = authorsQuery.List (); foreach (Author author in authors) comboBox.Items.Add(author.LastName + ", " + author.FirstName); } finally { session.Close(); }}}}

Пример Пусть одной из функций нашего приложения является вывод информации о всех авторах в формате HTML: public string GetAllAuthorsAsHTML(ISessionFactory factory) { ISession session = factory.OpenSession(); try { IQuery authorsQuery = session.CreateQuery("FROM Author"); IList authors = authorsQuery.List (); StringBuilder result = new StringBuilder(); result.Append(" ").Append(" "); foreach (Author author in authors) { result.Append(" ").Append(author.LastName + ", " + author.FirstName).Append(" "); result.Append(" Year of birth: ").Append(author.YearOfBirth.ToString()).Append(" "); } result.Append(" ").Append(" "); return result.ToString(); } finally { session.Close(); }}}}

Пример Недостатки использованного подхода: неоправданное дублирование; зависимость от конкретной реализации ORM; непрозрачность кода; невозможность протестировать код.

Схема

Пример Определим класс Repository: public class Repository { private ISession session; public Repository(ISession session) { this.session = session; } public IEnumerable GetAllAuthors() { IQuery authorsQuery = session.CreateQuery("FROM Author"); return authorsQuery.List (); }}}}

Пример Теперь функции, которые работают со списком авторов, можно переписать следующим образом: public void FillAuthorsComboBox( ComboBox comboBox, Repository repository) { IEnumerable authors = repository.GetAllAuthors(); foreach (Author author in authors) comboBox.Items.Add( author.LastName + ", " + author.FirstName); }

Пример Функция экспорта в HTML преобразуется следующим образом: public string GetAllAuthorsAsHTML(Repository repository) { IEnumerable authors = repository.GetAllAuthors(); StringBuilder result = new StringBuilder(); result.Append(" ").Append(" "); foreach (Author author in authors) { result.Append(" ").Append(author.LastName + ", " + author.FirstName).Append(" "); result.Append(" Year of birth: ").Append(author.YearOfBirth.ToString()).Append(" "); } result.Append(" ").Append(" "); return result.ToString(); }

Плюсы Сокращение дублирования; прозрачность кода; возможность создания фиктивного хранилища для упрощения тестирования; скрытие деталей реализации.

Specification Specification (спецификация) паттерн, который инкапсулирует логику отбора доменных объектов в отдельный объект.

Specification

Specification. Пример Предположим, что нам необходимо делать выборки авторов, удовлетворяющие разным критериям. Например, выбирать авторов, родившихся в определнный период или имя которых содержит заданное значение: public class Repository { public IEnumerable FindAuthors_BornBetween(int startYear, int endYear) { return session.QueryOver ().Where(a => a.YearOfBirth >= startYear && a.YearOfBirth (); } public IEnumerable FindAuthors_NameContains(string value) { return session.QueryOver ().Where(a => a.FirstName.Contains(value)).List (); }}}} Интерфейс класса Repository может стать неоправданно большим. Кроме того, такая реализация нарушает принцип открытости/закрытости.

Specification. Пример Решением является использование паттерна Спецификация. Рассмотрим пример применения данного паттерна: public interface ISpecification { Expression > IsSatisfiedBy(); } public class Repository { public IEnumerable FindAuthors( ISpecification specification) { return session.QueryOver ().Where(specification.IsSatisfiedBy()).List (); }}}}

Specification. Пример Класс, реализующий интерфейс спецификации и выполняющий проверку даты рождения на вхождение в определнный диапазон, будет выглядеть так: public class IsYearOfBirthInRange : ISpecification { private int endYear; private int startYear; public IsYearOfBirthInRange(int startYear, int endYear) { this.startYear = startYear; this.endYear = endYear; } public Expression > IsSatisfiedBy() { return author => author.YearOfBirth >= startYear && author.YearOfBirth

Specification. Пример Класс, реализующий интерфейс спецификации и анализирующий имя автора, будет следующим: public class AuthorNameContains : ISpecification { private string value; public AuthorNameContains(string value) { this.value = value; } public Expression > IsSatisfiedBy() { return author => author.FirstName.Contains(value); }}}}

Specification. Пример Рассмотрим теперь пример использования полученных классов. Выведем всех авторов, родившихся во второй половине XX века: public void DisplayAuthors(Repository repository) { IEnumerable authors = repository.FindAuthors(new IsYearOfBirthInRange(1950, 2000)); foreach (Author author in authors) Console.WriteLine(author.FirstName + " " + author.LastName); }

Specification Для того чтобы сделать выборку, удовлетворяющую нескольким условиям, можно применить паттерны компоновщик и декоратор следующим образом:

Specification Интерфейс спецификации следует расширить следующим образом: public interface ISpecification { Expression > IsSatisfiedBy(); ISpecification Or(ISpecification left); ISpecification And(ISpecification left); ISpecification Not(); }

Specification Класс составного условия будет следующим: public abstract class CompositeSpecification : ISpecification { public abstract Expression > IsSatisfiedBy(); public ISpecification Or(ISpecification right) { return new OrSpecification (this, right); } public ISpecification And(ISpecification right) { return new AndSpecification (this, right); } public ISpecification Not() { return new NotSpecification (this); }}}}

Specification Рассмотрим реализацию наследников упомянутого выше класса. Класс AndSpecification будет следующим: public class AndSpecification : CompositeSpecification { private ISpecification left; private ISpecification right; public AndSpecification(ISpecification left, ISpecification right) { this.left = left; this.right = right; } public override Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.And( left.IsSatisfiedBy(), right.IsSatisfiedBy())); }}}}

Specification Класс OrSpecification: public class OrSpecification : CompositeSpecification { private ISpecification left; private ISpecification right; public OrSpecification(ISpecification left, ISpecification right) { this.left = left; this.right = right; } public override Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.Or( left.IsSatisfiedBy(), right.IsSatisfiedBy())); }}}}

Specification Класс NotSpecification: public class NotSpecification : CompositeSpecification { private ISpecification wrapped; public NotSpecification(ISpecification wrapped) { this.wrapped = wrapped; } public override Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.Not(wrapped.IsSatisfiedBy())); }}}}

Specification Теперь классы конкретных условий должны наследовать класс CompositeSpecification: public class IsYearOfBirthInRange : CompositeSpecification { private int endYear; private int startYear; public IsYearOfBirthInRange(int startYear, int endYear) { this.startYear = startYear; this.endYear = endYear; } public override Expression > IsSatisfiedBy() { return author => author.YearOfBirth >= startYear && author.YearOfBirth

Specification Рассмотрим пример использования. Выберем всех авторов, которые родились не в первой половине XX века и имя которых содержит букву «А»: public static void DisplayAuthors(Repository repository) { ISpecification condition = ( (new IsYearOfBirthInRange(1950, 1999)).Not() ).And ( new AuthorNameContains("A") ); IEnumerable authors = repository.FindAuthors(condition); foreach (Author author in authors) Console.WriteLine(author.FirstName + " " + author.LastName); }

Specification Такая возможность языка C# 3.0, как методы расширения позволяет реализовать подобную функциональность следующим образом: public static class SpecificationUtils { public static ISpecification Or (this ISpecification left, ISpecification right) { return new OrSpecification (left, right); } public static ISpecification And (this ISpecification left, ISpecification right) { return new AndSpecification (left, right); } public static ISpecification Not (this ISpecification wrapped) { return new NotSpecification (wrapped); }}}}

Specification Класс AndSpecification будет выглядеть так: Остальные подобные классы реализуются аналогично. public class AndSpecification : ISpecification { private ISpecification left; private ISpecification right; public AndSpecification(ISpecification left, ISpecification right) { this.left = left; this.right = right; } public Expression > IsSatisfiedBy() { return Expression.Lambda >( Expression.And( left.IsSatisfiedBy(), right.IsSatisfiedBy())); }}}}

Specification Клиентский код остатся без изменений: public static void DisplayAuthors(Repository repository) { ISpecification condition = ( (new IsYearOfBirthInRange(1950, 1999)).Not() ).And ( new AuthorNameContains("A") ); IEnumerable authors = repository.FindAuthors(condition); foreach (Author author in authors) Console.WriteLine(author.FirstName + " " + author.LastName); }