Вы находитесь на странице: 1из 12

bЛабораторная 1 по ООБД

Задание: Переработать клиентскую программу программу с сервером MSSQL в


вариант LINQ to SQL
LINQ для баз данных
Рассмотрим LINQ to SQL — версию LINQ, предоставляющую доступ к базам данных
SQL, таким как Microsoft SQL Server.
Базы данных SQL, например, Microsoft SQL Server, сохраняют исходные данные в
таблицах, которые представляют собой группы строк и столбцов.
В противоположность этому С# (как и другие объектно-ориентированные языки)
сохраняют данные в объектах памяти. Объекты более сложны, чем таблицы, потому что
они имеют ассоциированный с ними код (методы), могут содержать в себе другие объекты
и т.д.
LINQ to SQL создает слой объектно - реляционного отображения (object-relational
mapping — ORM) между таблицами реляционной базы данных и объектами программы
С#.
В LINQ to SQL объектная модель, выраженная на языке C#, сопоставляется модели
данных реляционной базы данных. После этого операции с данными выполняются в
соответствии с объектной моделью.
В этом случае команды базы данных (например, INSERT) не выполняются в базе данных.
Вместо этого изменение значений и выполнение методов происходит в рамках объектной
модели. Если необходимо отправить запрос к базе данных или передать изменения, LINQ
to SQL преобразует операции объектной модели в корректные команды SQL и отправляет
эти команды в базу данных.
Суть проблемы, которая решается с помощью ORM-слоя, заключается в необходимости
преобразования объектных структур в памяти приложения в форму, удобную для
сохранения в реляционных базах данных, а также для решения обратной задачи —
развертывания реляционной модели в объектную, с сохранением свойств объектов и
отношений между ними.
Можно рассмотреть это преобразование для уже известных заказчиков, заказов и товаров
(рис. )

Рис. Связь реляционной БД с объектами C#


Создание кода для набора классов и коллекций, соответствующих структуре
существующей реляционной таблицы, утомительно и трудоемко, но благодаря объектно-
реляционному отображению LINQ to SQL, классы, соответствующие таблице базы
данных, создаются автоматически из самой базы данных, так что тратить время на это не
потребуется.
Чтобы добавить класс отображения LINQ to SQL для базы данных Northwind, которая
имеется на сервере MS SQL, установленном на компьютере, необходимо в панели Solution
Explorer из контекстного меню выбрать пункт Add, New Item. В диалоговом окне New
Item необходимо выбрат LINQ to SQL Class в качестве шаблона нового класса (рис. )

Рис. Окно для выбора класса LINQ to SQL


Добавим в проект соединение с базой данных Northwind. Для этого в окне Server Explore
нужно в контекстном меню выбрать пункт AddConnections. При этом в диалоговом окне
Choose Data Source следует выбрать Microsoft SQL Server Database File (Файл базы данных
Microsoft SQL Server) в списке Data Source (Источник данных), как показано на рис.

Тип источника
данных

Имя
файла
БД

Рис. Окно выбора файла БД для соединения


После этого в окне Server Explorer появится список таблиц БД
Нужную таблицу следует перетащить в окно класса DataClasses1.dbml (рис. )

Рис. Класс, полученный из таблицы БД

Выполнение запросов с помощью LINQ to SQL


На форме поместим компоненту listBox1 для вывода выбранных строк таблицы customer
БД Northwind и кнопку. Код, выполняемый при нажатии кнопки:
DataClasses1DataContext northWindDataContext = new DataClasses1DataContext();
var queryResults = from c in northWindDataContext.Customers
where c.Country == "USA" select new {
ID = c.CustomerID,Name = c.CompanyName,City = c.City,State = c.Region};
listBox1.Items.Clear();
foreach (var item in queryResults)
{listBox1.Items.Add(item);}
Классы, создаваемые LINQ to SQL, имеют поля таблиц в виде свойств, поэтому они
непосредственно используются в запросах.
Одним из наиболее мощных аспектов ORM является его способность автоматически
создавать объекты LINQ to SQL, которые помогут выполнять навигацию по отношениям
между связанными таблицами в базе данных.
Щелкнем на таблице Orders в окне Database Explorer и перетащим ее в панель
DataClasses1.dbml.
Это окно примет вид (рис. )
Рис. Два класса, полученных
из двух связанных таблиц БД

Добавим поле Orders к конструкции select запроса LINQ:


DataClasses1DataContext northWindDataContext = new DataClasses1DataContext();
var queryResults = from c in northWindDataContext.Customers
where c.Country == "USA"
select new {ID = c.CustomerID,Name = c.CompanyName,City = c.City,
State = c.Region,Orders = c.Orders;
Цикл вывода строк в listBox2 является вложенным: во внешнем цикле выводится
информация о заказчике, а во внутреннем – информация о заказах, связанных с
конкретным заказчиком
DataClasses1DataContext northWindDataContext = new DataClasses1DataContext();
var queryResults = from c in northWindDataContext.Customers
where c.Country == "USA"
select new {ID = c.CustomerID,Name = c.CompanyName,City = c.City,
Country = c.Country,Orders = c.Orders };
listBox2.Items.Clear();
foreach (var item in queryResults)
{listBox2.Items.Add("Заказчик: "+item.Name+" Страна: "+item.Country+
" Город: "+item.City+" заказов:"+Convert.ToString(item.Orders.Count));
listBox2.Items.Add("ID закаэа Дата заказа");
foreach (Order o in item.Orders)
{listBox2.Items.Add(Convert.ToString(o.OrderID) + " " + Convert.ToString(o.OrderDate));}
Агрегатный метод LINQ Count()используется для вывода количества заказов конкретного
заказчика.
Вид окна при выводе результатов приведен на рис.

}
Рис. Вывод взаимосвязанных данных

Можно расширить использование связей, добавив третий объект для таблицы Order
Details (рис. )
Рис. Три взаимосвязанных объекта в проекте

Теперь мы хотим посчитать суммы заказов. Для этого, не меняя запрос и внешний цикл
вывода информации о заказчике, добавим во внутренний цикл вывод суммы произведений
количества на стоимость единицы
listBox2.Items.Clear();
foreach (var item in queryResults)
{listBox2.Items.Add("Заказчик: "+item.Name+" Страна: "+item.Country+
" Город: "+item.City+" заказов:"+Convert.ToString(item.Orders.Count));
listBox2.Items.Add("ID закаэа Дата заказа Общая сумма");
foreach (Order o in item.Orders)
listBox2.Items.Add(Convert.ToString(o.OrderID) + " " + Convert.ToString(o.OrderDate)+" "+
Convert.ToString(o.Order_Details.Sum(od => od.Quantity * od.UnitPrice))); }}
Для получения суммы по всем строкам заказа применяется агрегатная операция LINQ
Sum(), которой передается лямбда-выражение:
od => od.Quantity * od.UnitPrice),
вычисляющее общую сумму каждого заказа.
Операции group и огderby в LINQ to SQL те же, что и в LINQ to Objects, но использование
источников данных SQL для каждого LINQ может опираться на возможности group и
orderby самой базы данных SQL, в зависимости от способа построения запроса.
Для получения суммы продаж по странаи следует записать три запроса: первый выдает
название страны и сумму продаж. Операция Sum(), использующая лямбда-выражение od
=> od. Quantity * od.UnitPrice
Используется для получения суммы всех единиц заказов.
Второй запрос группирует данные по странам, используя результаты предыдущего
запроса в качестве источника данных.
Этот запрос использует страну в качестве ключа для группировки результатов и
суммирования общих продаж (в данном случае Sum() суммирует общие продажи по всем
заказчикам в пределах страны), и операция вложена внутрь другого вызова Sum () для
суммирования продаж по всем заказам для каждого заказчикаr.
В последнем запросе данные упорядочиваются по суммам.
DataClasses1DataContext northWindDataContext=newDataClasses1DataContext();
var totalResults =
from c in northWindDataContext.Customers
select new {Country = c.Country, Sales =
c.Orders.Sum(o => o.Order_Details.Sum(od => od.Quantity *od.UnitPrice))};
var groupResults = from c in totalResults
group c by c.Country into eg
select new { TotalSales = eg.Sum(c => c.Sales), Country = eg.Key };
var orderedResults =
from eg in groupResults
orderby eg.Country descending
select eg;
listBox2.Items.Clear();
foreach (var item in orderedResults)
{ listBox2.Items.Add(item.Country+" "+Convert.ToString(item.TotalSales)); }
Каждый запрос (переменная типа var) генерирует оператор языка SQL, который
посылается базе данных.

Формы корректировки данных с помощью LINQ to SQL


Для того чтобы конечные пользователи могли взаимодействовать с приложением базы
данных, необходимо спроектировать набор форм для ввода данных.
Как правило, это требует большого объема рутинных действий для обновления объектов
из форм с последующим вызовом методов для запросов и обновления базы данных в
результате просмотра пользователем данных, их ввода и обновления.
С помощью модели ORM это делается легко путем нажатия ряда кнопок и написания
нескольких строк.
Добавьте к проекту новый источник данных, выбрав пункт меню Data, Add New Data
Source. Появится окно (рис. ), в котором выбирается Object.
Рис. Выбор источника данных

В следующем окне выбирается конкретный объект, в данном случае Customer (рис. ).

Рис. Выбор конкретного объекта

Аналогично выбирается второй объект Object. После этого окно Data Source примет вид
(рис. )
Рис. Окно Data Source

Развернем узел Customer, щелкнем по нему и в раскрывающемся списке выберем Details в


качестве типа элементов управления для их создания (рис. ).

Рис. Выбор детального способа


отображения информации

Щелчок по узлу Customer и перетаскивание его в окно визуального конструктора формы


приведет к появлению набора полей ввода данных наряду с двумя новыми объектами:
customerBindingSource и customerBindingNavigator (рис. ).

Рис. Форма с элементами управления


Аналогично перетаскивается объект Object, но в режиме DataGridView. Форма примет вид
(рис. )

Рис. Форма с элементами управления для двух связанных объектов


Строка кода, который подключает привязанные к данным поля к классу DataContext,
записывается в метод Form_Load():
customerBindingSource.DataSource = northwindDataContext.Customers;
Хотя элементы управления данными были сгенерированы для класса LINQ to SQL при
определении объекта в качестве источника данных, присваивание члена DataSource — вот
что сообщает С# о том, из какого экземпляра объекта следует наполнять элементы
управления.
Однако, как только начальный экземпляр найден, остальное происходит автоматически,
когда пользователь взаимодействует с элементами управления на форме, и ничего не
нужно кодировать самостоятельно!
Объект BindingNavigator имеет элементы для перемещения по элементам основного
объекта, добавления и удаления элемента. Это кнопки, образующие элемент. Кнопка
Сохранить изначально недоступна.
Запустив приложение, можно увидеть перемещение по объектам Customer с
отображением связанных с каждым объектом элементов Order (рис. 127).
Рис. Просмотр взаимосвязанных объектов

Нажатие кнопок Добавить и Удалить выполняет заложенные в них по умолчанию


действия. Чтобы сохранить результаты изменений, необходимо настроить кнопку
Сохранить. Эта кнопка имеет имя customerBindingNavigatorSaveItem. Ее свойство Enabled
нужно установить равным True, а в событии Click нужно записать строку
northwindDataContext.SubmitChanges();
, что и сохранит все сделанные изменения.
Конечно, данный подход не учитывает все сложные случаи, которые могут возникнуть. В
каждом конкретном случае нужно самим определить кнопки, переопределить действия
добавления, удаления и изменения, но часто LINQ to SQL облегчает работу.
Использование хранимых процедур базы данных с LINQ to SQL
Для представления хранимых процедур базы данных.LINQ to SQL использует методы
объектной модели, то есть методы класса DataContext.
Хранимые процедуры базы данных можно перетаскивать из файла базы данных в
объектную модель так же, как таблицы. Их также можно создавать в среде C# в окне
DataConnections.
Например, добавим к базе данных NORTHWIND процедуру CustomersByCity с
параметром param:
ALTER PROCEDURE [dbo].[Customers By City]
(@param1 VARCHAR(20))
AS
BEGIN
SELECT CustomerID, ContactName, CompanyName, City from Customers
as c where c.City=@param1
END
Эта процедура выбирает заказчиков из указанного города, задаваемого параметром.
Сохраним процедуру в базе данных и перетащим ее в объектную модель (рис. ).
Рис. Хранимая процедура базы данных, вставленная в объектную модель

Создадим на форме поле для ввода города и кнопку для вывода данных – результатов
запроса.
Код, выполняемый при нажатии кнопки:
DataClasses1DataContext northWindDataContext = new DataClasses1DataContext();
string param = textBox1.Text;
// Переменная для результатов, возвращаемых хранимой процедурой
var custquery = northWindDataContext.Customers_By_City(param);
// Выполнение хранимой процедуры
listBox1.Items.Clear();
foreach (var custOrdersDetail in custquery)
{listBox1.Items.Add(custOrdersDetail.CompanyName); }
param = "";
textBox1.Text = "";

Вам также может понравиться