17326

LINK to SQL

Лекция

Информатика, кибернетика и программирование

Лекция 11. LINK to SQL 10.1.2.1. Общие сведения После ознакомления с основными аспектами работы с запросами в C можно рассмотреть конкретный тип поставщика LINQ – LINQ to SQL. Отображение реляционных данных на объектную модель всегда было одной из наиболее сложных проблем при построе...

Украинкский

2013-06-30

251.7 KB

22 чел.

Лекция 11. LINK to SQL

10.1.2.1. Общие сведения

После ознакомления с основными аспектами работы с запросами в C# можно рассмотреть конкретный тип поставщика LINQLINQ to SQL.

Отображение реляционных данных на объектную модель всегда было одной из наиболее сложных проблем при построении объектно-ориентированных систем [3]. В большинстве случаев, запросы к базе данных пишутся на языке SQL, а их результат конвертируется в объекты (рис. 10.8). Разработчик вынужден одновременно работать с двумя различными представлениями данных, что значительно увеличивает трудозатраты на создание и поддержку программного продукта и увеличивает вероятность ошибок.

LINQ to SQL – простая, но достаточно мощная система объектно-реляционного отображения (ORM). По сравнению с традиционной технологией ADO.NET применение LINQ to SQL позволяет значительно упростить код, снизить вероятность ошибок и сократить время разработки проекта (рис. 10.9). Наибольший выигрыш при этом получат разработчики Web приложений, для которых, в новой версии ASP.NET предусмотрен специальный источник данных, позволяющий делать запросы непосредственно в Web странице.


Рис. 10.8.  Работа с реляционными данными по технологии ADO.NET


Рис. 10.9.  Работа с реляционными данными по технологии LINQ

10.1.2.2. Возможности LINQ to SQL

LINQ to SQL поддерживает все основные возможности, необходимые для разработчиков на SQL [8]. Можно запрашивать данные, вставлять, обновлять и удалять сведения из таблиц.

10.1.2.2.1. Выбор

Выборка (проекция) достигается написанием запроса LINQ на выбранном языке программирования и последующим выполнением этого запроса для получения результатов. Средства LINQ to SQL сами преобразуют все необходимые операции в требуемые операции SQL, которые вам знакомы.

В следующем примере извлекаются названий компаний клиентов из Москвы, которые затем отображаются в окне консоли:

// Northwnd наследуется от System.Data.Linq.DataContext

Northwnd nw = new Northwnd(@"northwnd.mdf");

var companyNameQuery =

   from cust in nw.Customers

   where cust.City == "Москва"

   select cust.CompanyName;

foreach (var customer in companyNameQuery)

{

   Console.WriteLine(customer);

}

=================================

// Northwnd inherits from System.Data.Linq.DataContext.

Northwnd nw = new Northwnd(@"northwnd.mdf");

// or, if you are not using SQL Server Express

// Northwnd nw = new Northwnd("Database=Northwind;Server=server_name;Integrated Security=SSPI");

var companyNameQuery =

   from cust in nw.Customers

   where cust.City == "London"

   select cust.CompanyName;

foreach (var customer in companyNameQuery)

{

   Console.WriteLine(customer);

}

10.1.2.2.2. Вставка

Для выполнения SQL Insert нужно добавить объекты в созданную объектную модель и вызвать метод SubmitChanges в DataContext. В следующем примере новый клиент и сведения о нем добавляются в таблицу Customers с помощью метода InsertOnSubmit:

// Northwnd наследуется от System.Data.Linq.DataContext.

Northwnd nw = new Northwnd(@"northwnd.mdf");

Customer cust = new Customer();

cust.CompanyName = "Компания";

cust.City = "Москва";

cust.CustomerID = "98128";

cust.PostalCode = "55555";

cust.Phone = "555-55-55";

nw.Customers.InsertOnSubmit(cust);

// В данном месте новый объект Customer добавлен в объектную модель.

// В LINQ to SQL изменение не будет записано в базу данных, пока не будет вызван метод SubmitChanges.

nw.SubmitChanges();

10.1.2.2.3. Обновление

Чтобы сделать Update записи в базе данных, сначала следует извлечь элемент и изменить его непосредственно в объектной модели. После изменения объекта необходимо вызвать метод SubmitChanges в DataContext, чтобы обновить базу данных.

В следующем примере извлекаются все клиенты из Москвы. Затем название города меняется с "Москва" на "Москва – Химки". Наконец, вызывается метод SubmitChanges для отправления изменений в базу данных:

Northwnd nw = new Northwnd(@"northwnd.mdf");

var cityNameQuery =

   from cust in nw.Customers

   where cust.City.Contains("Москва")

   select cust;

foreach (var customer in cityNameQuery)

{

   if (customer.City == "Москва")

   {

       customer.City = "Москва – Химки";

   }

}

nw.SubmitChanges();

10.1.2.2.4. Удаление

Чтобы выполнить операцию Delete для элемента, необходимо удалить его из коллекции, в которую он входит, а затем вызвать метод SubmitChanges в DataContext, чтобы применить изменение.

Примечание. LINQ to SQL не выполняет операцию каскадного удаления.

В следующем примере из базы данных извлекается клиент, CustomerID которого равен 98128. Затем, после подтверждения извлечения строки клиента, вызывается метод DeleteOnSubmit, необходимый для удаления объекта из коллекции. Наконец, вызывается метод SubmitChanges для передачи удаления в базу данных:

Northwnd nw = new Northwnd(@"northwnd.mdf");

var deleteIndivCust =

   from cust in nw.Customers

   where cust.CustomerID == "98128"

   select cust;

if (deleteIndivCust.Count() > 0)

{

   nw.Customers.DeleteOnSubmit(deleteIndivCust.First());

   nw.SubmitChanges();

}

10.1.2.3. Пример использования LINQ to SQL

Для создания объектной модели для базы данных, классы должны быть приведены в соответствие с сущностями, хранящимися в базе данных. Можно выделить три способа реализации такого приведения [8] – можно задавать атрибуты для существующих объектов, можно использовать специальное средство, позволяющее автоматически сгенерировать объекты и использовать утилиту командной строки SQLMetal.

  1.  Объектно-реляционный конструктор. Этот конструктор предоставляет многофункциональный пользовательский интерфейс для создания объектной модели из существующей базы данных. Данное средство, являющееся частью интегрированной среды разработки Visual Studio, лучше всего подходит для баз данных небольшого или среднего размера.
  2.  Средство создания кода SQLMetal. По своему набору параметров эта консольная программа несколько отличается от Объектно-реляционного конструктора. Данное средство лучше всего подходит для моделирования больших баз данных.
  3.  Редактор кода. Можно написать собственный код с помощью редактора кода Visual Studio или другого редактора кода. Этот подход может привести к большому числу ошибок, поэтому при наличии существующей базы данных, которую можно использовать для создания модели с помощью Объектно-реляционного конструктора или программы SQLMetal, использовать его не рекомендуется. Однако редактор кода становится ценным инструментом, когда требуется уточнить или изменить код, уже созданный с помощью других средств.

Используем последний способ, задав атрибуты для существующих объектов [3]:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data.Linq;

using System.Data.Linq.Mapping;

using System.Data.SqlClient;

namespace LinqtoSQL

{

   [Table(Name = "Customers")]

   public class Customer

   {

       [Column]

       public string CustomerID { get; set; }

       [Column]

       public string City { get; set; }

       public override string ToString()

       {

           return CustomerID + "\t" + City;

       }

   }

   class Program

   {

       static void Main(string[] args)

       {

           DataContext db = new DataContext

           (@"Data Source=.\SQLEXPRESS;

AttachDbFilename=|DataDirectory|\NORTHWND.MDF;

Integrated Security=True;

User Instance=True");

           var results = from c in db.GetTable<Customer>()

                         where c.City == "Москва"

                         select c;

           foreach (var c in results)

               Console.WriteLine("{0}\t{1}", c.CustomerID, c.City);

           Console.ReadKey();

       }

   }

}

В этом приложении есть класс Customer, который отображает таблицу Customers, и имеет поля CustomerID и City, отображающие поля этой таблицы. Объект класса DataContext задает входную точку в базу данных и имеет метод GetTable, который возвращает коллекцию определенного типа, в данном случае типа Customer.

В результате выполнения программы на экран будут выведены идентификаторы и города проживания тех заказчиков, которые живут в Москве.

На рис. 10.10 приведено отображение LINQ to SQL

Рис. 10.10.  Отображение LINQ to SQL

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

Для начала необходимо добавить файл LINQ to SQL classes. Затем в окне Server Explorer следует развернуть дерево базы данных Northwind и перетащить нужные таблицы и хранимые процедуры в окно файла отображения на панель методов. Для данного примера будет достаточно перетащить хранимую процедуру Ten Most Expensive Products (рис. 10.11).

Для начала необходимо добавить файл LINQ to SQL classes. Затем в окне Server Explorer следует развернуть дерево базы данных Northwind и перетащить нужные таблицы и хранимые процедуры в окно файла отображения на панель методов. Для данного примера будет достаточно перетащить хранимую процедуру Ten Most Expensive Products (рис. 10.11).


увеличить изображение
Рис. 10.11.  Создание объекта отображения хранимой процедуры

Хранимая процедура извлекает из таблицы Products 10 самых дорогих продуктов и их цены:

USE [Northwind]

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

ALTER procedure [dbo].[Ten Most Expensive Products] AS

SET ROWCOUNT 10

SELECT Products.ProductName AS TenMostExpensiveProducts, Products.UnitPrice

FROM Products

ORDER BY Products.UnitPrice DESC

Для того чтобы вызвать эту процедуру из программы на языке C# и вывести результаты, достаточно написать всего 3 строки кода:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data.Linq;

using System.Data.Linq.Mapping;

namespace LinqtoSQL

{

   class Program

   {

       static void Main(string[] args)

       {

           var db = new northwindDataContext();

           foreach (var r in db.Ten_Most_Expensive_Products())

               Console.WriteLine(r.TenMostExpensiveProducts + "\t" + r.UnitPrice);

           Console.ReadKey();

       }

   }

}

Обратите внимание, что входная точка в базу данных теперь создается конструктором класса northwindDataContext (в общем случае класс будет называться так: {имя файла отображения}DataContext), которому больше не нужно передавать параметром строку соединения в явном виде.

10.1.3. ADO.NET Entity Framework

ADO.NET Entity Framework (EF) – объектно-ориентированная технология доступа к данным, является object-relational mapping (ORM) решением для .NET Framework от Microsoft [9]. Предоставляет возможность взаимодействия с объектами как посредством LINQ в виде LINQ to Entities, так и с использованием Entity SQL. Для облегчения построения Веб-решений используется как ADO.NET Data Services, так и связка из Windows Communication Foundation и Windows Presentation Foundation, позволяющая строить многоуровневые приложения, реализуя один из шаблонов проектирования MVC, MVP или MVVM.

Платформа ADO.NET Entity Framework позволяет разработчикам создавать приложения для доступа к данным, работающие с концептуальной моделью приложения, а не напрямую с реляционной схемой хранения. Ее целью является уменьшение объема кода и усилий по обслуживанию приложений, ориентированных на обработку данных. Приложения Entity Framework дают следующие преимущества [10].

  1.  приложения могут работать концептуальной моделью в терминах предметной области – в том числе с наследуемыми типами, сложными элементами и связями;
  2.  приложения освобождаются от жестких зависимостей от конкретного ядра СУБД или схемы хранения;
  3.  сопоставления между концептуальной моделью и схемой, специфичной для конкретного хранилища, могут меняться без изменения кода приложения;
  4.  разработчики имеют возможность работать с согласованной моделью объектов приложения, которая может быть сопоставлена с различными схемами хранения, которые, возможно, реализованы в различных системах управления данными;
  5.  несколько концептуальных моделей могут быть сопоставлены с единой схемой хранения;
  6.  поддержка интегрированных в язык запросов (LINQ) обеспечивает во время компиляции проверку синтаксиса запроса относительно концептуальной модели.

10.1.3.1. Компоненты Entity Framework

Платформа Entity Framework представляет собой набор технологий ADO.NET, обеспечивающих разработку приложений, связанных с обработкой данных [10]. Архитекторам и разработчикам приложений, ориентированных на обработку данных, приходится учитывать необходимость достижения двух совершенно различных целей. Они должны моделировать сущности, связи и логику решаемых бизнес-задач, а также работать с ядрами СУБД, используемыми для сохранения и получения данных. Данные могут распределяться по нескольким системам хранения данных, в каждой из которых применяются свои протоколы, но даже в приложениях, работающих с одной системой хранения данных, необходимо поддерживать баланс между требованиями системы хранения данных и требованиями написания эффективного и удобного для обслуживания кода приложения.

В Entity Framework разработчики получают возможность работать с данными, представленными в форме относящихся к конкретным доменам объектов и свойств, таких как клиенты и их адреса, не будучи вынужденными обращаться к базовым таблицам и столбцам базы данных, где хранятся эти данные. Такая возможность появляется благодаря переходу на более высокий уровень абстракции, на котором разработчики могут работать с данными, применяя меньший объем кода для создания и сопровождения приложений, ориентированных на работу с данными.

Платформа Entity Framework является компонентом .NET Framework, поэтому приложения Entity Framework можно запускать на любом компьютере, на котором установлен .NET Framework 3.5 с пакетом обновления 1 (SP1).

10.1.3.1.1. Применение концептуальных моделей на практике

Давно известный и широко применяемый принцип проектирования в моделировании данных состоит в разделении модели данных на следующие три части: концептуальная модель, логическая модель и физическая модель. Концептуальная модель определяет сущности и связи в моделируемой системе. Логическая модель для реляционной базы данных обеспечивает нормализацию сущностей и связей в целях создания таблиц с ограничениями внешнего ключа. В физической модели учитываются возможности конкретной системы обработки данных путем определения зависящих от ядра базы данных подробных сведений о хранении данных, которые касаются секционирования и индексирование.

Физическая модель совершенствуется администраторами базы данных в целях повышения производительности, но программисты, которые разрабатывают код приложения, в основном вынуждены ограничиваться работой с логической моделью, подготавливая SQL-запросы и вызывая хранимые процедуры. Концептуальные модели в основном используются как инструмент для представления и обмена мнениями по поводу требований к приложению, поэтому чаще всего служат в качестве почти неизменных схем, которые рассматриваются и обсуждаются на ранних стадиях проекта, после чего перестают быть предметом внимания.

Платформа Entity Framework придает значимость концептуальным моделям, позволяя разработчикам выполнять запросы к сущностям и связям в концептуальной модели; при этом для перевода этих операций в команды, зависящие от источника данных, применяется сама платформа Entity Framework. Это позволяет отказаться от применения в приложениях жестко заданных зависимостей от конкретного источника данных. Концептуальная модель, модель хранения и их сопоставление выражаются во внешней спецификации, известной также как модель Entity Data Model (EDM). Модель хранения и сопоставление могут изменяться по мере необходимости, не требуя изменений в концептуальной модели, классах данных и коде приложения. Модели хранения зависят от поставщика, поэтому можно работать с согласованной концептуальной моделью через различные источники данных.

Модель EDM определяется следующими тремя файлами модели и сопоставления, которые имеют соответствующие расширения имен файлов.

  1.  Файл на языке CSDL (с расширением CSDL) определяет концептуальную модель.
  2.  Файл на языке SSDL (с расширением SSDL). Определяет модель хранения данных, которая называется также логической моделью.
  3.  Файл на языке MSL (с расширением MSL) определяет сопоставление модели хранения и концептуальной модели.

В Entity Framework эти файлы модели и сопоставления на основе XML используются для преобразования операций создания, чтения, обновления и удаления, выполняемых над сущностями и связями концептуальной модели, в эквивалентные операции в источнике данных (рис. 10.12). Модель EDM поддерживает даже сопоставление сущностей в концептуальной модели с хранимыми процедурами в источнике данных.


Рис. 10.12.  Разработка сущностной модели данных

В модели EDM сущности и их связи моделируются с использованием двух основных типов.

  1.  EntityType: абстрактная спецификация подробных сведений о структуре данных в домене приложения.
  2.  AssociationType: логическое соединение между типами.

Схема проектирования модели EDM определяет структуру, семантику, ограничения и связи сущностей в домене приложения. В реализации служб объектов модели EDM концептуальная схема сопоставляется с EDM-схемой, которая содержит метаданные, описывающие модель хранения (обычно это таблицы в базе данных). Концептуальная схема используется для формирования классов программируемой модели объектов, которая применяется в коде приложения. Концептуальная схема и схема хранения используются также в технологии Entity Framework для проверки, выполнения запросов и обновления данных приложения во время выполнения

10.1.3.1.2. Сопоставление объектов и данных

При использовании объектно-ориентированного программирования для взаимодействия с системами хранения данных возникают сложности. Безусловно, организация классов часто напоминает организацию таблиц реляционной базы данных, но такое соответствие не идеально. Несколько нормализованных таблиц часто соответствуют единственному классу, а связи между классами представлены иначе, чем связи между таблицами.

В существующих решениях была предпринята попытка устранить этот разрыв, часто называемый "несоответствием типов данных" (impedance mismatch), путем сопоставления с реляционными таблицами и столбцами только объектно-ориентированных классов и свойств. Вместо данного традиционного подхода в Entity Framework реляционные таблицы, столбцы и ограничения внешнего ключа логических моделей преобразуются в сущности и связи концептуальных моделей. Это позволяет достичь большей гибкости при определении объектов и оптимизации логической модели. С помощью инструментов Entity Data Model формируются расширяемые классы данных, основанные на концептуальной модели. Эти классы являются разделяемыми классами, которые могут быть расширены с помощью дополнительных членов, добавленных разработчиком. Классы, сформированные для определенной концептуальной модели, являются производными от базовых классов, предоставляющих службы объектов для материализации сущностей в виде объектов, а также для отслеживания и сохранения из менений. Разработчики могут использовать эти три класса для работы с сущностями и связями как с объектами, связанными свойствами навигации.

10.1.3.1.3. Компоненты платформы Entity Framework

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

  1.  Модель Entity Data Model (EDM) служит центром приложения Entity Framework. Она задает схему проекта, которая используется для построения программируемых классов, используемых кодом приложения.
  2.  Компонент Object Services позволяет программистам работать с классами CLR, созданными из концептуальной модели. Он также обеспечивает инфраструктурную поддержку для приложения Entity Framework, предоставляя такие службы, как управление состоянием, отслеживание изменений, разрешение идентификаторов, загрузка и переход по связям, распространение изменений объектов в модификации базы данных, а также поддержку запросов для Entity SQL.
  3.  Компонент LINQ to Entities обеспечивает поддержку LINQ при запросах к сущностям. Компонент LINQ to Entities позволяет разработчикам писать запросы к базе данных на одном из поддерживаемых языков программирования .NET Framework, например Visual Basic или Visual C#.
  4.  Язык Entity SQL подобен языку SQL и не зависит от типа хранилища. Он предназначен для создания запросов к сложным графам объектов, основанных на модели EDM, а также для управления ими.
  5.  Поставщик EntityClient расширяет модель поставщика ADO.NET путем доступа к данным в терминах сущностей и связей концептуальной модели. Он выполняет запросы, которые используют язык Entity SQL. Entity SQL предоставляет базовый язык запросов, который позволяет поставщику EntityClient связываться с базой данных.
  6.  Компонент метаданных ADO.NET управляет метаданными для всей платформы Entity Framework как во время разработки, так и во время выполнения. Все метаданные, связанные с моделями и сопоставлениями, доступны через интерфейсы метаданных, которые не зависят от механизма, используемого для хранения метаданных. Текущий механизм хранения использует файлы, которые основаны на трех диалектах XML: языке CSDL, языке SSDL и языке MSL.
  7.  Приложение Entity Framework включает изменяющийся набор средств, которые создают сопоставления и разделяемые классы, представляющие сущности концептуальной модели.
  8.  Приложение Entity Framework включает обновленный поставщик данных SqlClient, который поддерживает канонические деревья команд.

На рис. 10.13 показаны связи различных доступных пользователям интерфейсов программирования в приложении Entity Framework [10, 11]. Стрелка вниз обозначает запрос к источнику данных, а стрелка вверх – возвращаемые данные. Службы объектов создают каноническое дерево команд, которое представляет работу LINQ to Entities или Entity SQL с концептуальной моделью. Поставщик EntityClient преобразует это каноническое дерево команд, основанное на модели EDM, в новое каноническое дерево команд, содержащее эквивалентные операции для источника данных.


Рис. 10.13.  Компоненты Entity Framework

10.1.3.1.4. Средства работы с моделью EDM

Наряду со средой выполнения Entity Framework, .NET Framework 3.5 с пакетом обновления 1 включает генератор моделей EDM (EdmGen.exe). Программа командной строки соединяется с источником данных и формирует модель EDM на основе сопоставления типа "один к одному" между сущностями и таблицами. В этой программе используется также файл концептуальной модели (с расширением CSDL) для формирования файла уровня объектов, содержащего классы, которые представляют типы сущностей и контекст ObjectContext.

Visual Studio 2008 включает в себя обширный набор поддерживаемых инструментов для создания и обслуживания модели EDM в приложении Visual Studio. Конструктор Entity Data Model поддерживает создание усовершенствованных сценариев сопоставления (таких как наследование типа "одна таблица на тип" и "одна таблица на иерархию"), а также разделение сущностей, которые сопоставлены с несколькими таблицами.

10.1.3.2. Создание сущностной модели данных

Для примера создания EDM будет использоваться база данных Northwind.

C помощью мастера EDM, который предоставляет список объектов, которые возможно смоделировать (рис. 10.14), включим все таблицы в модель, тем самым произведя взаимно-однозначное сопоставление таблиц сущностям [12].


Рис. 10.14.  Мастер EDM

Источник: Обзор ADO.NET Entity Framework [12]

Помимо создания файлов CSDL, SSDL и MSL для всех таблиц в Northwind, мастер также создаст набор классов, основываясь на CSDL, представляющий модель. Часть этих классов показана на рис. 10.15 в окне Class View.

Мастер EDM отследил связь между таблицами Customers и Orders в базе данных и создал соответствующую ассоциацию в концептуальной модели. Поэтому класс Customers содержит свойство перемещения Orders, позволяющее разработчикам переходить от экземпляра класса Customers к любому из экземпляров класса Orders для него.


Рис. 10.15.  Классы

Источник: Обзор ADO.NET Entity Framework [12]

10.1.3.3. Разбор CSDL

Метаданные, содержащиеся в CSDL-файле, содержат списки сущностей, представленных элементами EntityType, и связей, представленных элементами Association, относящихся к типу AssociationType. Далее показан фрагмент CSDL-файла, определяющий EntityType:

<EntityType Name="Customers" Key="CustomerID">

 <Property Name="CustomerID" Type="String" Nullable="false"

MaxLength="4000" FixedLength="true" />

 <Property Name="CompanyName" Type="String" Nullable="false"

MaxLength="4000" />

 <Property Name="ContactName" Type="String" MaxLength="4000" />

 <Property Name="ContactTitle" Type="String" MaxLength="4000" />

 <Property Name="Address" Type="String" MaxLength="4000" />

 <Property Name="City" Type="String" MaxLength="4000" />

 <Property Name="Region" Type="String" MaxLength="4000" />

 <Property Name="PostalCode" Type="String" MaxLength="4000" />

 <Property Name="Country" Type="String" MaxLength="4000" />

 <Property Name="Phone" Type="String" MaxLength="4000" />

 <Property Name="Fax" Type="String" MaxLength="4000" />

 <NavigationProperty Name="Orders"

Relationship="NorthwindModel.FK_Orders_Customers"

FromRole="Customers" ToRole="Orders" />

</EntityType>

Сущности содержат списки скалярных свойств, определяющих их. Атрибут Key показывает, какие свойства являются ключевыми. Составные ключи выделяются разделением имен свойств пробелами. Сущности также могут содержать специальные свойства, называемые NavigationProperty. Они определяют переходы от одной сущности к другой через ассоциации.

В следующем фрагменте CSDL определятся AssociationType между Customer и относящимися к нему Orders:

<Association Name="FK_Orders_Customers">

 <End Role="Customers" Type=

        "NorthwindModel.Customers"

     Multiplicity="0..1" />

 <End Role="Orders" Type=

        "NorthwindModel.Orders" Multiplicity="*" />

</Association>

Элементы End в AssociationType указывают участвующих в ассоциации. В этом примере сущность Customers ассоциирована с сущностью Orders. Также сущность Customers может быть связана с любым числом сущностей Orders, что определяется атрибутом Multiplicity.

В то время как элементы EntityType и AssociationType определяют типы сущностей области и отношения между ними, элементы EntitySet и AssociationSet определяют их области применения. Все "наборы", которые должны быть сгруппированы вместе, содержатся внутри элемента EntityContainer.

Следующий фрагмент CSDL демонстрирует EntityContainer и часть его содержимого:

<EntityContainer Name="NorthwindEntities">

 <EntitySet Name="Customers"

     EntityType="NorthwindModel.Customers" />

 <EntitySet Name="Orders"

     EntityType="NorthwindModel.Orders" />

 <AssociationSet Name="FK_Orders_Customers"

         Association="NorthwindModel.FK_Orders_Customers">

   <End Role="Customers" EntitySet="Customers" />

   <End Role="Orders" EntitySet="Orders" />

 </AssociationSet>

</EntityContainer>

Этот фрагмент включает наборы EntitySet для типов EntityType Customers и Orders: Здесь же объявляется ассоциация AssociationSet FK_Orders_Customers. Таким образом, этот фрагмент определяет сущности Customers и Orders, а также связь между ними.

10.1.3.4. Сопоставление хранилищу

Файл SSDL определяет структуру реляционных данных в базе данных. В нем также используются элементы XML EntityType и AssociationType, в этом случае для объявления структур таблиц и существующих в базе данных внешних ключей соответственно. Пространство имен файла SSDL основано на имени базы данных, использованной в EDM, тогда как элемент EntityContainer назван в соответствии со схемой базы данных. EntityContainer содержит наборы элементов EntitySet и AssociationSet, которые объявляют экземпляры таблиц и отношений, представленных элементами EntityType и AssociationType. Каждому набору EntitySet в файле SSDL соответствует таблица в базе данных.

Если EDM создается на основе базы данных, то файлы CSDL и SSDL достаточно похожи. Это потому, что модели созданы прямо из базы данных, и концептуальная модель сопоставляется логическому хранилищу напрямую. Файл MSL содержит прямое соответствие CSDL и SSDL. Все запросы на основе такой EDM транслируются в созданные команды SQL. Entity Framework также поддерживает использование хранимых процедур вместо создания запросов SQL.

Для сопоставления модели (CSDL) хранилищу (SSDL) используется элемент EntityContainerMapping. Атрибут StorageEntityContainer показывает название контейнера EntityContainer в хранилище, а атрибут EdmEntityContainer показывает соответствующий EntityContainer в модели. Для сопоставления набора EntitySet модели набору EntitySet хранилища требуется элемент EntitySetMapping. Атрибут Name определяет название набора EntitySet модели, а атрибут TableName определяет название соответствующего набора EntitySet в хранилище. Каждое свойство модели сопоставляется хранилищу посредством элемента ScalarProperty. Пример файла MSL:

<cs:EntitySetMapping cs:Name="Products">

 <cs:EntityTypeMapping cs:TypeName="NorthwindModel.Products">

   <cs:TableMappingFragment cs:TableName="Products">

     <cs:ScalarProperty cs:Name="ProductID" cs:ColumnName="ProductID" />

     <cs:ScalarProperty cs:Name="ProductName"

         cs:ColumnName="ProductName" />

     <cs:ScalarProperty cs:Name="QuantityPerUnit"

         cs:ColumnName="QuantityPerUnit" />

     <cs:ScalarProperty cs:Name="UnitPrice" cs:ColumnName="UnitPrice" />

     <cs:ScalarProperty cs:Name="UnitsInStock"

         cs:ColumnName="UnitsInStock" />

     <cs:ScalarProperty cs:Name="UnitsOnOrder"

         cs:ColumnName="UnitsOnOrder" />

     <cs:ScalarProperty cs:Name="ReorderLevel"

         cs:ColumnName="ReorderLevel" />

     <cs:ScalarProperty cs:Name="Discontinued"

         cs:ColumnName="Discontinued" />

     <cs:Condition cs:ColumnName="Discontinued" cs:Value="0"/>

   </cs:TableMappingFragment>

 </cs:EntityTypeMapping>

</cs:EntitySetMapping>

10.1.3.5. Определение наследования

EDM также поддерживает модели, не соответствующие базе данных взаимно-однозначно. Например, используя базу данных Northwind, можно создать класс, например, называющийся DiscontinuedProducts, который наследует все свойства класса Products, но содержит только продукты, значение поля Discontinued для которых равно 1. Это упрощенная схема наследования, но она показывает, как применить наследование в EDM.

Первым шагом по созданию класса DiscontinuedProducts в концептуальной модели является открытие файла CSDL, создание нового типа EntityType, называющегося DiscontinuedProducts, и установка его атрибута BaseType в значение NorthwindModel.Products (схема и название базового EntityType). Порожденный тип EntityType наследует свойства EntityType Products, включая ключи. Дополнительный код CSDL для всего описанного выглядит так:

<EntityType Name="DiscontinuedProducts" BaseType="NorthwindModel.Products"/>

Следующим шагом в этом процессе является открытие файла MSL и удаление атрибутов TypeName и TableName элемента EntitySetMapping Products. Теперь они будут устанавливаться отдельно для каждого конкретного типа EntityType. Затем необходимо создать дочерний элемент EntityTypeMapping и установить TypeName как NorthwindModel.Products. Для каждого EntityType, порожденного от базового EntityType, EntitySetMapping должен включать элемент EntityTypeMapping. Далее нужно создать дочерний элемент EntityTypeMapping, называющийся TableMappingFragment, и установить для его атрибута TableName значение Products. В целом, эти шаги переносят сопоставление с элемента EntitySetMapping на более низкий и детальный уровень.

Далее необходимо закомментировать сопоставление свойства Discontinued и добавить элемент Condition, указывающий, что включены будут только записи со значением поля Discontinued, равным 0. После этого нужно скопировать целиком XML фрагмент EntityTypeMapping, поменять значение атрибута Name на DiscontinuedProducts и поменять значение в условии на 1.

Далее показан фрагмент файла MSL, в котором происходит сопоставление унаследованной сущности:

<cs:EntitySetMapping cs:Name="Products">

 <cs:EntityTypeMapping cs:TypeName="NorthwindModel.Products">

   <cs:TableMappingFragment cs:TableName="Products">

     <cs:ScalarProperty cs:Name="ProductID" cs:ColumnName="ProductID" />

     <cs:ScalarProperty cs:Name="ProductName"

         cs:ColumnName="ProductName" />

     <cs:ScalarProperty cs:Name="QuantityPerUnit"

         cs:ColumnName="QuantityPerUnit" />

     <cs:ScalarProperty cs:Name="UnitPrice" cs:ColumnName="UnitPrice" />

     <cs:ScalarProperty cs:Name="UnitsInStock"

         cs:ColumnName="UnitsInStock" />

     <cs:ScalarProperty cs:Name="UnitsOnOrder"

         cs:ColumnName="UnitsOnOrder" />

     <cs:ScalarProperty cs:Name="ReorderLevel"

         cs:ColumnName="ReorderLevel" />

     <!--<cs:ScalarProperty cs:Name="Discontinued"

         cs:ColumnName="Discontinued" />-->

     <cs:Condition cs:ColumnName="Discontinued" cs:Value="0"/>

   </cs:TableMappingFragment>

 </cs:EntityTypeMapping>

 <!--</cs:EntitySetMapping>

<cs:EntitySetMapping cs:Name="DiscontinuedProducts">-->

 <cs:EntityTypeMapping cs:TypeName=

       "NorthwindModel.DiscontinuedProducts">

   <cs:TableMappingFragment cs:TableName="Products">

     <cs:ScalarProperty cs:Name="ProductID" cs:ColumnName="ProductID" />

     <cs:ScalarProperty cs:Name="ProductName"

         cs:ColumnName="ProductName" />

     <cs:ScalarProperty cs:Name="QuantityPerUnit"

         cs:ColumnName="QuantityPerUnit" />

     <cs:ScalarProperty cs:Name="UnitPrice" cs:ColumnName="UnitPrice" />

     <cs:ScalarProperty cs:Name="UnitsInStock"

         cs:ColumnName="UnitsInStock" />

     <cs:ScalarProperty cs:Name="UnitsOnOrder"

         cs:ColumnName="UnitsOnOrder" />

     <cs:ScalarProperty cs:Name="ReorderLevel"

         cs:ColumnName="ReorderLevel" />

     <cs:Condition cs:ColumnName="Discontinued" cs:Value="1"/>

   </cs:TableMappingFragment>

 </cs:EntityTypeMapping>

</cs:EntitySetMapping>

10.1.3.6. Сопоставление нескольким таблицам

Другим способом уйти в EDM от строгого взаимно-однозначного сопоставления модели хранилищу является сопоставление одной сущности в модели нескольким таблицам в хранилище. Между таблицами Contacts и ContactNameSplit в базе данных Northwind есть взаимно-однозначная связь, и можно объединить их в одну сущность в модели. Для примера создадим в модели сущность, включающую все поля таблицы Contacts и поля Title и Name из таблицы ContactNameSplit.

Первым изменением является добавление двух дополнительных свойств в элементе EntityType Contacts в файле CSDL: Name и Title. Эти два новых свойства в модели теперь должны быть сопоставлены хранилищу в файле MSL. Необходимо изменить элемент EntitySetMapping для EntitySet Contacts, чтобы представлять сопоставление нескольким таблицам, например, удалив атрибуты TableName и TypeName. Эти атрибуты объявляются в элементе EntitySetMapping, только если набор EntitySet в модели взаимно-однозначно сопоставлен набору EntitySet в хранилище.

Поскольку сопоставление набора EntitySet модели набору EntitySet хранилища для Contacts было удалено, необходимо создать ему замену. Такой заменой является дочерний элемент EntityTypeMapping. Их необходимо создать два – по одному для представления каждой из таблиц Contacts и ContactNameSplit в хранилище. Элементы EntityTypeMapping определяют атрибут TypeName для каждого из наборов EntitySet.

Внутри каждого из элементов EntityTypeMapping помещен дочерний элемент, называющийся TableMappingFragment. Этот элемент включает атрибут TableName, соответствующий набору EntitySet в хранилище. В TableMappingFragment определены все элементы ScalarProperty, сопоставляющие свойства модели хранилищу. Далее показан обновленный элемент EntitySetMapping Contacts, который теперь сопоставляет таблицы Contacts и ContactSplitName хранилища одному набору EntitySet модели:

<cs:EntitySetMapping cs:Name="Contacts">

 <cs:EntityTypeMapping cs:TypeName="NorthwindModel.Contacts">

   <cs:TableMappingFragment cs:TableName="Contacts">

     <cs:ScalarProperty cs:Name="ContactID"

         cs:ColumnName="ContactID" />

     <cs:ScalarProperty cs:Name="ContactType"

         cs:ColumnName="ContactType" />

     <cs:ScalarProperty cs:Name="CompanyName"

         cs:ColumnName="CompanyName" />

     <cs:ScalarProperty cs:Name="ContactName"

         cs:ColumnName="ContactName" />

     <cs:ScalarProperty cs:Name="ContactTitle"

         cs:ColumnName="ContactTitle" />

     <cs:ScalarProperty cs:Name="Address" cs:ColumnName="Address" />

     <cs:ScalarProperty cs:Name="City" cs:ColumnName="City" />

     <cs:ScalarProperty cs:Name="Region" cs:ColumnName="Region" />

     <cs:ScalarProperty cs:Name="PostalCode"

         cs:ColumnName="PostalCode" />

     <cs:ScalarProperty cs:Name="Country" cs:ColumnName="Country" />

     <cs:ScalarProperty cs:Name="Phone" cs:ColumnName="Phone" />

     <cs:ScalarProperty cs:Name="Extension"

         cs:ColumnName="Extension" />

     <cs:ScalarProperty cs:Name="Fax" cs:ColumnName="Fax" />

     <cs:ScalarProperty cs:Name="PhotoPath"

         cs:ColumnName="PhotoPath" />

   </cs:TableMappingFragment>

 </cs:EntityTypeMapping>

 <cs:EntityTypeMapping cs:TypeName="ContactNameSplit">

   <cs:TableMappingFragment cs:TableName="ContactNameSplit">

     <cs:ScalarProperty cs:Name="ContactID" cs:ColumnName="ID" />

     <cs:ScalarProperty cs:Name="Name" cs:ColumnName="Name" />

     <cs:ScalarProperty cs:Name="Title" cs:ColumnName="Title" />

   </cs:TableMappingFragment>

</cs:EntityTypeMapping>

10.1.3.7. Использование EntityClient

Доступ к концептуальной модели Entity Framework может быть организован тремя способами: EntityClient, Object Services, LINQ to Entities

Рассмотрим первый их них.

EntityClient абстрагирован от логического хранилища, поскольку он взаимодействует с концептуальной моделью посредством своего собственного текстового языка, называющегося Entity SQL. Все запросы Entity SQL, выполняемые через EntityClient, компилируются в деревья команд, посылаемые в хранилище. Преобразование запросов Entity SQL через концептуальную модель и далее в хранилище обеспечивается Entity Framework.

Классы EntityClient похожи на классы распространенных поставщиков ADO.NET. Например, запросы EntityClient выполняются в объекте EntityCommand, которому необходим объект EntityConnection для подключения к EDM. Хотя EntityClient взаимодействует с сущностями EDM, он не возвращает экземпляры сущностей, а вместо этого возвращает все результаты в виде объекта DbDataReader. При помощи DbDataReader EntityClient может возвращать стандартный набор строк и столбцов, либо представление более сложной иерархии данных.

На следующем примере показано использование EntityClient для подключения к концептуальной модели и получения списка заказчиков из Москвы:

string city = "Москва";

using (EntityConnection cn = new EntityConnection("Name=NorthwindEntities"))

{

   cn.Open();

   EntityCommand cmd = cn.CreateCommand();

   cmd.CommandText =

        "SELECT VALUE c FROM NorthwindEntities.Customers " +

  "AS c WHERE c.City = @city";

   cmd.Parameters.AddWithValue("city", city);

   DbDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

   while (rdr.Read())

         Console.WriteLine(rdr["CompanyName"].ToString());

   rdr.Close();

}

EntityConnection может воспринимать полную строку подключения к концептуальному слою или ее название в файле App.Config. Строка подключения содержит перечень файлов метаданных (файлов CSDL, MSL и SSDL), а также строку подключения к хранилищу, зависящую от конкретной базы данных:

"metadata=.\NorthwindEntities.csdl|.\NorthwindEntities.ssdl|.\NorthwindEntities.msl;provider=System.Data.SqlClient;

provider connection string='

Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;

Integrated Security=True; User Instance=True'"

Код в примере показывает, как создать объект EntityConnection и выполнить для него команду EntityCommand. Запрос, написанный на Entity SQL, обращается к набору EntitySet Customers в EDM.

10.1.3.8. Использование служб Object Services

Другим способом взаимодействия с данными, представленными EDM, является использование служб Object Services. Службы Object Services предоставляют возможность загружать объекты и следовать любым связям, определенным в EDM. Службы Object Services используют EntityClient для получения данных. Службы Object Services добавляют разрешение идентификаторов, что при использовании DataSet приходится делать вручную. Они также обеспечивают неизменность объектов и отслеживание изменений через события, чтобы позволять явные загрузку и сохранение. За счет этого снижается число обращений к серверу.

Службы Object Services позволяют возвращать списки объектов напрямую – можно возвращать как проекции, так и определенные сущности. Например, пользуясь Object Services, можно получить List<Customers>, как определено в EDM. Объекты Customers можно просмотреть, изменить значения, а затем сохранить данные в базе данных.

При использовании проекций при помощи служб Object Services возвращаемые данные не будут обновляемым объектом. Поскольку проекции возвращают конкретные свойства сущностей, а не сущности целиком, службы Object Services не могут сохранить изменения в спроецированных данных обратно в базу данных. Если необходимо обновить данные, лучшим вариантом будет возвращать сущность целиком и не использовать проекцию.

Можно использовать службы Object Services для выполнения запросов Entity SQL или можно писать запросы, используя LINQ to Entities. Следующий пример демонстрирует запрос на Entity SQL, выполняемый через службы Object Services для получения списка заказчиков:

string city = "Москва";

ObjectQuery<Customers> query = northwindContext.CreateQuery<Customers>(

   "SELECT VALUE c FROM Customers AS c WHERE c.City = @city",

    new ObjectParameter("city", city));

foreach (Customers c in query) Console.WriteLine(c.CompanyName);

В EDM EntityContainer представлен классом, производным от ObjectContext (в этом примере northwindContext). Класс ObjectContext реализует интерфейс ObjectQuery<T>, позволяя создавать запросы, используя Entity SQL и LINQ.

Метод CreateQuery принимает параметризованный оператор Entity SQL, определяющей запрос, возвращающий список сущностей Customers. Собственно выражение SQL, обращающееся к базе, выполняется при итерации по ObjectQuery<Customers> оператором foreach.

10.1.3.9. Использование LINQ to Entities

С помощью служб Object Services можно выполнять динамические запросы, написанные на Entity SQL, для взаимодействия с сущностями EDM. Но в Entity Framework также можно работать со строго типизированными классами EDM, используя LINQ to Entities. Например, в только что продемонстрированном примере запрос на Entity SQL через Object Services может быть изменен для выполнения на LINQ to Entities, вот так:

string city = "Москва";

var query = from c in northwindContext.Customers

           where c.City == city

           select c;

foreach (Customers c in query) Console.WriteLine(c.CompanyName);

В этом примере кода основанный на тексте синтаксис Entity SQL заменен на строго типизированный синтаксис LINQ, поддерживаемый в C# 3.0.

Теперь вспомним, как был создан в EDM тип EntityType, называющийся DiscontinuedProducts, произведенный от Products. Возможности EDM по наследованию могут быть использованы совместно с LINQ и Object Services для получения списка продуктов, которые больше не поддерживаются. Обратите внимание, что в следующем примере не указывается, что значение поля Discontinued должно быть равно 1. Вместо этого, тип для сущности продукта сверяется с производным EntityType DiscontinuedProducts, что в свою очередь задействует условие, которое было создано в сопоставлении (файле MSL), чтобы создать подходящее выражение SQL для получения только неподдерживаемых продуктов:

var query = from p in northwindContext.Products

           where p is DiscontinuedProducts

           select p;

foreach (Products p in query) Console.WriteLine(p.ProductName);

Также можно создавать запросы, использующие преимущества встроенных отношений EDM (определяемых набором AssociationSet). Например, список заказов для заказчиков из Москвы может быть получен посредством следующего выражения запроса LINQ:

var query = from o in northwindContext.Orders

           where o.Customers.City == "Москва"

           select o;

foreach (Orders o in query) Console.WriteLine(o.OrderID);

Этот пример начинается с сущности Orders и использует ее свойство перемещения Customers для просмотра свойства City. Заказы от заказчиков не из Москвы полностью отфильтровываются. Поскольку возвращается список сущностей Orders, сущности могут быть изменены, и изменения могут быть сохранены в базе данных. Сохранение изменений в базе данных может быть выполнено при помощи метода SaveChanges.

Следующий пример получает список заказчиков из Москвы и устанавливает значение свойства Country для каждого из них в "Россия". Изменения сохраняются в StateManager, но не заносятся в базу данных, пока не вызывается метод SaveChanges:

var query = from c in northwindContext.Customers

           where c.City == "Москва"

           select c;

foreach (Customers c in query) c.Country = "Россия";

northwindContext.SaveChanges();

Также можно создать новый экземпляр сущности и добавить его в EDM, используя метод AddObject объекта ObjectContext. В следующем примере показано, как добавить новую категорию в таблицу базы данных Categories:

Categories newCat = new Categories();

newCat.CategoryName = "Другое";

northwindContext.AddObject(newCat);

northwindContext.SaveChanges();

int newCatID = newCat.CategoryID;

Сначала создается экземпляр сущности Categories и устанавливается значение его свойства CategoryName. Затем новая категория добавляется в EDM вызовом метода AddObject. Когда вызывается метод SaveChanges, создается оператор SQL, сохраняющий новую Category в базе данных и возвращает идентификатор CategoryID для новой строки.

Когда между сущностями есть связи, вам может потребоваться ассоциировать новую сущность с уже существующей. Например, можно создать новую сущность Orders и связать ее свойство Customers с существующей сущностью Customers. Хотя в таблице Orders в базе данных есть поле CustomerID, EDM представляет эту связь в объектно-ориентированном стиле, используя свойство Customers для обращения к существующей сущности Customers:

Orders newOrder = new Orders();

newOrder.OrderDate = DateTime.Today;

Customers cust = northwindContext.Customers.Where(

   "it.CustomerID = 'ALFKI'").First();

newOrder.Customers = cust;

northwindContext.AddObject(newOrder);

northwindContext.SaveChanges();

10.1.4. Ключевые термины

Linq, Linq to SQL, ADO .NET Entity Framework.

10.2. Domain-Driven Design

10.2.1. Общие сведения

В заключение лекции рассмотрим практику Проблемно-ориентированного проектирования, которая получила в последнее время достаточно широкую известность и популяризируется, как отдельными специалистами в программной инженерии, так и крупными корпорациями, вроде Microsoft в том же ADO .NET Entity Framework.

Проблемно-ориентированное проектирование (Domain-Driven Design, DDD) является подходом к разработке программного обеспечения для решения сложных задач, глубоко связывающем реализацию программной систем с развивающейся моделью бизнес-концепций [13].

DDD – это набор принципов и схем, помогающих разработчикам создавать изящные системы объектов. При правильном применении оно приводит к созданию программных абстракций, которые называются моделями предметных областей [14]. В эти модели входит сложная бизнес-логика, устраняющая промежуток между реальными условиями бизнеса и кодом.

Проблемно-ориентированное проектирование имеет следующие свойства [15]:

  1.  фокусировка проекта на основной проблемной (предметной) области (домене) и бизнес-логике этой области;
  2.  базирование всего проектирования на модели;
  3.  введение творческого сотрудничества между техническими экспертами и экспертами в проблемной области, чтобы максимально понять концептуальную суть проблемы.

Проблемно-ориентированное проектирование не является отдельной технологией или методологией. DDD предоставляет набор методов и терминов для того, чтобы применять архитектурные решения, которые ускорят программные проекты, имеющие дело со сложными проблемными областями.

Термин DDD был придуман Эриком Эвансом в его книге "Domain-Driven Design: Tackling Complexity in the Heart of Software" [16].

Основными определениями DDD являются:

  1.  Домен (проблемная область) – это сфера интересов, поле деятельности, область знаний. Предметная область, к которой пользователь применяет программу, является доменом программного обеспечения.
  2.  Модель – это система абстракций, которая описывает выбранные аспекты домена и может использоваться для решения проблем, связанных с доменом.
  3.  Общеупотребительный язык (Ubiquitous Language) – это язык, структурированный в модели домена и используемый всеми членами команды, разрабатывающими программное обеспечение.
  4.  Контекст – это ситуация, в которой предложение или требование имеет строго определенное значение.

Главной целью проблемно-ориентированного проектирования является получение единственной, объединенной модель.

Предпосылками для успешного использования DDD для разработки программного обеспечения являются:

  1.  Сложная предметная область;
  2.  Опытная проектная команда, использующая ООП;
  3.  Есть доступ к экспертам в данной проблемной области;
  4.  Процесс разработки повторяем.

Рассмотрим основные аспекты Domain-Driven Design (рис. 10.16) [17]:

  1.  Модель;
  2.  Архитектура;
  3.  Дизайн/проектирование.


Рис. 10.16.  Основные аспекты Domain-Driven Design

Модель области должна обладать следующими свойствами:

  1.  возможность реализации программного обеспечения по данной модели;
  2.  модель должна быть достаточно проста для понимания;
  3.  всеми членами команды должен использоваться общеупотребительный язык;
  4.  всеми членами команды для определенных частей программной системы и проблемной области должен использоваться одинаковый контекст модели;
  5.  модель должна постоянно подвергаться переработки с целью выявления базовых концепций и объединения фрагментированных "подмоделей" в единую модель.

В своей книге Эрик Эванс сосредотачивает внимание на описании уровня домена, который является одним из общих уровней в объектно-ориентированной системе с многослойной архитектурой, и описывает основные артефакты, которыми можно выразить, создать или восстановить модель предметной области [16]:

  1.  Сущность (Entity) – это объект, который не определяется своими атрибутами (свойствами), а скорее является целостным и тождественным.
  2.  Объект со значением (Value Object) – это объект, который имеет атрибуты, определяющие его свойства, но не имеет никакой концептуальной тождественности.
  3.  Агрегат (Aggregate) – это коллекция объектов, которая связана корневым (составным) объектом. Составной объект гарантирует совместимость изменений, сделанных в пределах агрегата.
  4.  Службы (Services) – если операция концептуально не принадлежит никакому объекту, ее можно реализовать с помощью служб. Концепцию служб называют шаблон проектирования "Искусственный" (Pure Fabrication) в GRASP.
  5.  Репозитории (Repositories) – для того чтобы восстанавливать объекты домена, методы должны делегироваться специализированному объекту Репозиторий таким образом, чтобы можно было легко обмениваться альтернативными реализациями хранения.
  6.  Фабрики (Factories) – для того, чтобы создавать объекты домена, методы должны делегироваться специализированному объекту Фабрика таким образом, чтобы можно было легко обмениваться альтернативными реализациями.

DDD не привязан к конкретной технологии, однако соблюдать DDD будет не так просто, без наличия хороших средств и практик в арсенале, таких как: TDD-фреймворк, ORM, возможность реализации Persistence Ignorance, IoC-контейнер (Inversion of Control) и возможностей AOP (Аспектно-Ориентированного Программирования). Практичная ценность этих средств заключается в том, что они позволять изолировать модель предметной области, что является ключевой целью DDD.

В промышленных приложениях Domain-Driven Design использует ряд шаблонов, часть которых описана в книге Эрика Эвенса, но, это не отменяет применение объектно-ориентированного подхода, включающего GoF-шаблоны, шаблоны Мартина Фаулера, описанные в его PoEAA, шаблоны GRASP и т.д.

Проблемно-ориентированное проектирование ни в коем случае не отрицает применения практик разработки, таких как:

  1.  Объектно-ориентированное проектирование;
  2.  Шаблоны проектирования (Design Patterns);
  3.  Принципы проектирования S.O.L.I.D.;
  4.  Разработка TDD.

DDD лишь дополняет их. Поиск подходящей модели и абстракций в сложных сценариях требует значительных знаний в сфере объектно-ориентированного подхода, и достаточного опыта применения различных принципов, шаблонов и практик, а не просто DDD, как может показаться.

C DDD так же тесно связана такая тема, как DDDD: Distributed Domain Driven Design (Распределенный DDD) [18]. DDDD – это Domain-Driven Design в распределенных сценариях. В настоящее время существует не так много ресурсов, посвященных DDDD. Если коротко, то DDDD покрывает проблему реализации сообщений и DDD, разделение команд и запросов (Command Query Separation (CQS)), помогает реализовать данный подход.

Найти хорошие примеры реализации систем с применением Проблемно-ориентированного проектирования очень сложно, потому что DDD реализуется в приложениях, используемых в довольно сложных областях, и, как правило, являющихся коммерческими проектами. Однако можно найти несколько неплохих проектов, в которых можно проследить некоторые идеи реализации шаблонов [18]:

  1.  Проект Тима Маккарти, описанный в деталях в его книге [19]. Он описывает не только применение шаблонов, но так же акцентирует внимание в разработке модели предметной области с точки зрения . Проект так же интересен тем, что построен на .NET 3.5 и демонстрирует силу современного подхода связывания данных с моделью предметной области (data binding, реализация шаблона MVVM). Так же его стиль примечателен умением выделять абстракции и повторно используемый код.
  2.  Billy McCafferty разрабатывает open source фреймворк, сфокусированный на , под названием S#arp Architecture [20]. У него есть очень хорошее описание, включающее в себя шаблоны и подходы, используемые в фреймворке. Фреймворк нацелен на разработку ASP.NET MVC приложений с применением NHibernate.
  3.  C# Domain-Driven Design sample application (ndddsample), это приложение, разрабатываемое Джимми Нильссоном, демонстрирует разбиение приложения на ключевые слои с точки зрения [21]. Так же демонстрируется практическое применение шаблонов building block в предметной области перевозки грузов, описанной в его книге [22]. Этот проект основан на совместной работе компании Эрика Эвенса "Domain Language" и шведской консалтинговой компании "Citerus".

10.2.2. Ключевые термины

.

10.3. Краткие итоги

Language Integrated Query (LINQ) – проект Microsoft по добавлению синтаксиса языка запросов, напоминающего SQL, в языки программирования платформы .NET Framework.

LINQ представляет собой набор расширений языка, поддерживающий формирование запросов данных способом, безопасным по типам. Запрашиваемые данные могут быть

Все операции запроса LINQ состоят из трех различных действий.

  1.  получение источника данных;
  2.  создание запроса;
  3.  выполнение запроса.

Запросы LINQ основаны на универсальных типах, которые впервые были представлены в .NET Framework версии 2.0.

Основные операции запроса в LINQ:

  1.  получение источника данных;
  2.  фильтрация;
  3.  упорядочение;
  4.  группировка;
  5.  соединение;
  6.  выбор (Проецирование).

LINQ используется не только для извлечения данных. Это также мощное средство для преобразования данных:

  1.  соединение нескольких входных последовательностей в одну выходную;
  2.  выбор подмножества каждого исходного элемента;
  3.  преобразование находящихся в памяти объектов в XML;
  4.  выполнение операций над исходными элементами.

Операции запросов LINQ строго типизированы в источнике данных, в самом запросе и при выполнении запроса.

В LINQ можно использовать синтаксис запроса или синтаксис метода:

  1.  методы расширения стандартных операторов запросов;
  2.  лямбда-выражения;
  3.  возможность компоновки запросов.

LINQ to SQL – простая, но достаточно мощная система объектно-реляционного отображения (ORM).

LINQ to SQL поддерживает все основные возможности, необходимые для разработчиков на SQL. Можно запрашивать данные, вставлять, обновлять и удалять сведения из таблиц.

Можно выделить три способа создания объектной модели для базы данных:

  1.  объектно-реляционный конструктор;
  2.  средство создания кода SQLMetal;
  3.  редактор кода.

ADO.NET Entity Framework (EF) – объектно-ориентированная технология доступа к данным, является object-relational mapping (ORM) решением для .NET Framework от Microsoft.

Платформа Entity Framework содержит следующие компоненты:

  1.  Модель Entity Data Model (EDM).
  2.  Компонент Object Services.
  3.  Компонент LINQ to Entities
  4.  Язык Entity SQL
  5.  Поставщик EntityClient
  6.  Компонент метаданных ADO.NET
  7.  Набор средств, которые создают сопоставления и разделяемые классы, представляющие сущности концептуальной модели.
  8.  Поставщик данных SqlClient

Проблемно-ориентированное проектирование (Domain-Driven Design, ) является подходом к разработке программного обеспечения для решения сложных задач, глубоко связывающем реализацию программной систем с развивающейся моделью бизнес-концепций.

Основными определениями являются:

  1.  Домен.
  2.  Модель.
  3.  Общеупотребительный язык.
  4.  Контекст.
  5.  


 

А также другие работы, которые могут Вас заинтересовать

75215. Образование английского национального языка 37.5 KB
  Fisk fisker рыба – древне-английский Sun – sunner сын К концу X века господство было преодолено образовались Уэссекские королевства. К концу средне-английского периода начало XV века грамматический строй сильно изменился. С конца XV века образование раннего ново-английского языка XVI – конец XVII первые десятилетия XVIII. К концу XV века появляются первые типографии.
75217. Понятие литературного языка 36 KB
  Понятие литературного языка Литературный язык играет очень важную роль. Это нормированный язык. Свойства: Нормированность Поливалентность многофункциональность Общеобязательность Стилистическая дифференцированность Функциональная дифференцированность Носит наддиалектный характер носители диалектов понимают этот язык. Например койне может использоваться носителями разных диалектов Имеет свою письменность Норма может быть различной в разные периоды существования языка.
75219. Язык как предмет языкознания. Язык и речь 21.65 KB
  Определений языка очень много. Самое известное дал Ферденанд де Соссюр(швейцарский лингвист): Язык — это система произвольных знаков.
75221. Социолингвистика. Макросоциолингвистика и Микросоциолингвитсика 20 KB
  Социолингвистика область в которой рассматривается проблематика и вопросы соотношения языка и общества. Керри Вопросами связанными с проблемами соотношения языка и общества занимались и до 20-ого века но термин Социолингвистика появился...