Upload
xanto
View
85
Download
0
Embed Size (px)
DESCRIPTION
Высокоуровневые методы информатики и программирования Лекция 30 Работа с БД с использованием технологий связывания. Технология LINQ. LINQ to DataSet LINQ to SQL. LINQ to DataSet. «LINQ to DataSet » это новая технология ADO.NET. Позволяет выполнять LINQ запросы к объектам DataSet . - PowerPoint PPT Presentation
Citation preview
Высокоуровневые методы информатики и
программирования
Лекция 30
Работа с БД с использованием технологий связывания
Технология LINQ
LINQ to DataSetLINQ to SQL
LINQ to DataSet
• «LINQ to DataSet» это новая технология ADO.NET. Позволяет выполнять LINQ запросы к объектам DataSet.
• Можно выполнять LINQ запросы к типизированным DataSet
• Для работы с не типизированным DataSet нужно использовать метод запрос LINQ сделать нельзя!!!
Работа с не типизированным DataSetstring cnStr = @"Data Source=(local)\SQLEXPRESS;Initial Catalog=Northwind; Integrated Security=True";// создаем адаптер SqlDataAdapter da = new SqlDataAdapter("select * from Customers", cnStr);SqlCommandBuilder cmb = new SqlCommandBuilder(da); // создаем другие команды адаптера
DataSet ds = new DataSet(); // создаем DataSetda.Fill(ds, “Customers”); // заносим из БД таблицу в DataSet
DataTable tbl = ds.Tables[“Customers”]; // получаем ссылку на таблицу (не обязательно)
// выводим данные записей на печатьforeach(DataRow r in tbl.Rows) Console.WriteLine("id = {0}, name = {1};",r["CustomerID"],r["ContactName"]); Console.WriteLine("============");
// пример LINQ запроса к нетипизированной таблицеvar set = from c in tbl.AsEnumerable() where ((string)c["City"] == "London") select c; foreach (var r in set) Console.WriteLine("id = {0}, city = {1};", r["CustomerID"], r["City"]);
LINQ запрос типизированному DataSet
using AdoSample.NorthwindDSTableAdapters; // AdoSample – название проекта…
CustomersTableAdapter ca = new CustomersTableAdapter(); NorthwindDS ds = new NorthwindDS();ca.Fill(ds.Customers);
var results = from c in ds.Customers where c.City == "London” select c;foreach (var c in results) Console.WriteLine("{0}\t{1}", c.CustomerID, c.City);
Получение ссылки на одну запись в типизированном DataSet
try{ NorthwindDataSet.CustomersRow cr = ds1.Customers.SingleOrDefault(c => c.City == "ЛОНДОН"); if (cr != null) cr.City = "London";}catch (Exception ex){// более чем одна запись
MessageBox.Show(ex.Message);}
Пояснение LINQ запроса
Запрос следующего вида:var results = from c in ds.Customers where c.City == "London" select c;Можно прочитать как:Из объектов с входящих во множество
Customers, которые удовлетворяют условию с.City == “London” выбрать объекты с
LINQ to SQL • «LINQ to SQL» это новая технология семейства технологий ADO.NET. Она работает только с
Microsoft SQL Server.
• Основная цель LINQ to SQL является обеспечение согласованности между реляционными БД и программной логикой взаимодействия с ними. LINQ to SQL позволяет встроить доступ к данным в код программы.
• При программировании с помощью LINQ to SQL скрываются множество типов ADO.NET, таких как SqlConnection, SqlCommand, or SqlDataAdapter.
• Вместо того, чтобы обрабатывать реляционную БД в виде потока записей, можно рассматривать их в виде коллекций объектов определенного класса – класса сущностей.
Для работы с технологией LINQ to SQL требуется
• Добавить к проекту ссылку (Reference) на компонент: System.Data.Linq.dll
• Задать в программе используемые пространства имен using System.Data.Linq;using System.Data.Linq.Mapping;
Классы сущностей (entity class)
• Классы сущностей (entity classes) это классы программы, которые представляют данные содержащиеся в реляционной БД, с которой выполняется работа.
• С программной точки зрения классы сущностей это описания классов, которые аннотированы с помощью специальных атрибутов технологии «LINQ to SQL» (таких, как [Table] и [Column]), которые связывают их с физическими таблицами в БД.
• Например, класс сущностей для таблицы Customers:
[Table(Name = "Customers")]
public class Customer
{
public string CustomerID;
// ...
public string City;
}
• Большинство атрибутов «LINQ to SQL» определены в пространстве имен System.Data.Linq.Mapping.
• В Visual Studio 2008 (и SDK Framework 3.5) включены специальные программы, которые автоматически создают классы сущностей, требуемые для работы приложения.
Атрибуты класса сущностей
• Атрибут Table. С ним можно задавать следующие параметры: – Name – имя таблицы, которой соответствует, описываемый класс
сущностей.– Например:[Table (Name = xxxxx)]
• Атрибут Column. С ним можно задавать следующие параметры: – Name – имя соответствующей колонки в таблице;– DbType – тип поля записи;– CanBeNull – может ли быть значение null у поля записи.– IsPrimaryKey – указание, что поле является первичным ключом
(!!! Если первичный ключ не указан, то таблицу будет только для чтения ReadOnly !!!).
– Например: [Column (IsPrimaryKey=true)]
Пример описания класса сущностей
[Table(Name = "Customers")] // <- атрибут таблицы public class Customer { [Column (IsPrimaryKey=true)] // <- атрибут поля public string CustomerID { get; set; } [Column] // <- атрибут поля public string City { get; set; }
public override string ToString() { return CustomerID + "\t" + City; } }
Пример описания класса сущностей
[Table(Name = "Person.Contact")]public class Contact{ [Column(DBType = "int not null", IsPrimaryKey=true, IsDBGenerated=true)] public int ContactID; [Column(DBType = "nvarchar(8) not null")] public string Title; [Column(DBType = "nvarchar(50) not null")] public string FirstName; [Column(DBType = "nvarchar(50) not null")] public string MiddleName; [Column(DBType = "nvarchar(50) not null")] public string LastName; [Column(DBType = "nvarchar(50) not null")] public string EmailAddress; [Column(DBType = "int")] public int EmailPromotion; [Column(DBType = "bit")] public byte NameStyle; [Column(DBType = "varchar(40)")] public string PasswordHash; [Column(DBType = "varchar(40)")] public string PasswordSalt;}
Класс DataContext• После того, как описан класс сущностей запросы к СУБД передаются с помощью класса
DataContext.• Данный класс отвечает за трансляцию LINQ запросов в соответствующие SQL запросы и
передачу их конкретной БД.
• В некотором смысле DataContext похож на объект Connection, так как он также требует строку соединения.
• Однако, в отличии от класса Connection, класс DataContext имеет методы, которые связывают результаты выполнения запроса (выборку записей) с описанными классами сущностей.
• Класс DataContext описывает способ получения экземпляров класса сущностей, которые могут использоваться в программе.
• После получения экземпляров сущностей можно менять их состояние любым желательным способом (добавлять, изменять и т.п.) и предоставлять измененный объект назад для последующей обработки. В этом смысле класс DataContext похож на класс DataAdapter.
Методы DataContext• Конструктор:
DataContext ctx = new DataContext(<строка соединения>)
• Методы: – проверки соединения с базой данных DatabaseExists() – если true, то
соединение выполнено успешно.– получение таблицу
Table<имя таблицы> GetTable<имя таблицы>()
Например:Table<Inventory> invTable = ctx.GetTable<Inventory>();
– Метод сохранения изменений SubmitChanges()
ctx.SubmitChanges();
Класс Table<>
• Описывает таблицу указанного типа в базе данных. • Типизированный класс, для которого задается
используемый им тип данныхTable <Customers> tbc;
• Хранит объекты классов сущностей, того класса, который указан в угловых скобках.
• Предоставляет методы для работы LINQ запросов.• Свойство IsReadOnly возвращает true если таблица
описана только для чтения из БД.
Методы класса Table<>• Для получения ссылки на объект класса Table<> используется метод
GetTable<> класса DataContext:DataContext cnt = new DtaContext(strconn) ;
Table<MyTable> tbl = cnt.GetTable<MyTable>;
• Добавления новой записи в таблицу InsertOnSubmit()tbl.InsertOnSubmit(object);
• Удаление записи из таблицы DeleteOnSubmit() tbl.DeleteOnSubmit(object);
Пример: …
Получение одного объекта таблицы
• С помощью метода SingleOrDefault класса Table<> (если объектов больше 1, то генерируется исключение)DataContext dcn = new DataContext(cnStr);Table<MyCustomer> customers = dcn.GetTable<MyCustomer>();MyCustomer mc = customers.SingleOrDefault(c => c.CustomerID == "CONSH");if(mc != null) mc.City = "ЛОНДОН";dcn.SubmitChanges();
• C помощью метода FirstOrDefault класса Table<>var first = dcx.Customers.FirstOrDefault(c => (c.City == "London"));
• C помощью метода Fitst() коллекции IEnumerable<>:var row = (from c in customers where c.City == “Moscow” select c).First();
Пример работы с таблицей
// Создаем объект класса DataContextDataContext db = new DataContext(cnStr);// получаем объект класса Table<> для класса// сущностей InventoryTable<Inventory> invTable = db.GetTable<Inventory>();// создаем выборку всех элементов класса LINQ запросvar inv = from c in invTable select c;// выводим на экран элементы выборкиforeach (var car in inv)
Console.WriteLine(car.ToString());
LINQ запрос к DataContext
var db = new DataContext (@"Data Source=.\sqlexpress;Initial Catalog=Northwind");
var results = from c in db.GetTable<Customer>() where c.City == "London" select c;
foreach (var c in results) Console.WriteLine("{0}\t{1}", c.CustomerID, c.City);
Описание класса сущностей [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; } }
Добавление записи в БД// создаем новый экземпляр класса сущностейTable <Customer> tbc = ctx.GetTable<Customer>()
Customer newCust = new Customer ();// задаем его свойстваnewCust.ID = 1111;newCust.City = “Moscow";
// заносим созданный объект в контекстtbc.InsertOnSubmit(newCust);
// заносим изменения в БДctx.SubmitChanges();
Изменение колонок записи// находим нужную записьvar row = (from c in ctx.Customers
where c.City == “Moscow"select c).First();
// меняем значение полейrow.City = “Berlin";
// переносим изменения в БДctx.SubmitChanges();
Строго типизированный DataContext
• Описаниеclass NorthwindDatabase : DataContext{
public Table<Products> Products {get {return this.GetTable<Products>};
}public NorthwindDatabase(string connectionString): base(connectionString){ . . .}
}• Использование// Содание объекта NorthwindDatabaseNorthwindDatabase db = new NorthwindDatabase(cnStr);
// Теперь можно использовать поле Products foreach (var car in from c in db.Products select c)
Console.WriteLine(car.ToString());
Удаление записи// ищем записьvar row = (from c in ctx.Customers
where (c.CustomerID == 1212) select c).First());
// удаляем из контекстаctx.Inventories.DeleteOnSubmit(row);
// удаляем из базы данныхctx.SubmitChanges();
Автоматическое создание типизированного DataContext
Дизайнер LINQtoSQL
Автоматически формируемые классы
• Класс типизированного контекста – содержит свойства соответствующие таблицам.
• Классы сущностей, объекты которых соответствуют записям всех таблиц, включенных в типизированный контекст. Классы сущностей содержат:– Свойства соответствующие полям таблицы.– Связи один-ко-многим со стороны «многие» реализуются в виде
свойства, которое возвращает соответствующую им запись из связанной таблицы.
– Связи один-ко-многим со стороны «один» реализуются в виде свойств – коллекций, которые содержат соответствующие им записи из связанной таблицы.
Связь между объектами классов• Запрос к архиву работы сотрудников в подразделениях компании• Все отношения между таблицами реализованы с помощью связи между объектами классов:
– Например: dep.Employee.Contact.LastName
// Use a variant to hold the EmployeeDepartmentHistories// Use LINQ to query the database, passing in the last namevar DepartmentHistories = from dep in db.EmployeeDepartmentHistories where dep.Employee.Contact.LastName == txtLastName.Text
select dep;// Loop through the values and display in the list boxforeach (EmployeeDepartmentHistory edh in DepartmentHistories){ StringBuilder sb = new StringBuilder(edh.Employee.Contact.FirstName); sb.Append("\t"); sb.Append(edh.Employee.Contact.LastName); sb.Append("\t"); sb.Append(edh.Department.Name); sb.Append("\t"); sb.Append(edh.Employee.VacationHours.ToString()); lstResults.Items.Add(sb.ToString());}
ХМL файл соответствия(*.dbml)
• Создается вручную дизайнером типизированного DataContext• Используется только дизайнером для создания файлов с описаниями классов<?xml version="1.0" encoding="utf-8"?>
<Database Name="AdventureWorks"
Class="AdventureWorksDataContext"
xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
<Connection Mode="AppSettings" ConnectionString=
"Data Source=MASTER\SQLEXPRESS;Initial Catalog=AdventureWorks;Integrated Security=True“
SettingsObjectName="TypedDataContext.Properties.Settings"
SettingsPropertyName="AdventureWorksConnectionString"
Provider="System.Data.SqlClient" />
<Table Name="HumanResources.Department" Member="Departments">
<Type Name="Department">
<Column Name="DepartmentID“ Type="System.Int16" DbType="SmallInt NOT NULL IDENTITY“
IsPrimaryKey="true" IsDbGenerated="true“ CanBeNull="false" />
<Column Name="Name“ Type="System.String“ DbType="NVarChar(50) NOT NULL“ CanBeNull="false" />
<Column Name="GroupName“ Type="System.String" DbType="NVarChar(50) NOT NULL"
CanBeNull="false" />
<Column Name="ModifiedDate“ Type="System.DateTime" DbType="DateTime NOT NULL"
CanBeNull="false" />
</Type>
</Table>
</Database>
SqlMetalфайл *.dbml файл *.desiner.csс описаниями классов
Конструкторы типизированного класса DataContext
• // По умолчанию - Default ConstructorAdventureWorksDataContext db = new AdventureWorksDataContext();
• // С объектом ConnectionAdventureWorksDataContext db = new AdventureWorksDataContext(IDbConnection);
• // с именем исходного файла соответствия - mapping fileAdventureWorksDataContext db = new AdventureWorksDataContext(string);
• // С объектом Connection и именем файла задания соответствияAdventureWorksDataContext db = new AdventureWorksDataContext(IDbConnection, MappingSource);
• // с именем файла соответствия и MappingSource классомAdventureWorksDataContext db = new AdventureWorksDataContext(String, MappingSource);
Методы типизированного DataContext
• Типизированный DataContext содержит специальные методы – для вставки записей (Insert<TableName>)
• Например: partial void InsertDepartment(Department instance);
– для изменения записей (Update<TableName>)• Например:
partial void UpdateDepartment(Department instance);
• для удаления записей (Update<TableName>)• Например:
partial void DeleteDepartment(Department instance);
Пример LINQ запроса к типизированному DataContext
string cnStr = @"Data Source=(local)\SQLEXPRESS;Initial Catalog=Northwind; Integrated Security=True";
NortwindDCDataContext dcx = new NortwindDCDataContext(cnStr);
var results = from c in dcx.Customers where c.City == "London" select c;
foreach (var c in results) Console.WriteLine("{0}\t{1}", c.CustomerID, c.City);
Запрос к нескольким таблицам• LINQ запрос к двум таблица, включенным в типизированный
DataContext:var labels = (from c in dcx.Customers join o in dcx.Orders on c.CustomerID equals o.CustomerID select new { name = c.ContactName, address = o.ShipAddress }).Distinct();
foreach (var c in labels) Console.WriteLine("contact name = {0}\taddress = {1}",
c.name, c.address);
Работа с хранимыми процедурами<Function Name="dbo.uspGetEmployeeManagers" Method="uspGetEmployeeManagers"> <Parameter Name="EmployeeID" Parameter="employeeID” Type="System.Int32" DbType="Int" /> <ElementType Name="uspGetEmployeeManagersResult"> <Column Name="RecursionLevel" Type="System.Int32" DbType="Int" CanBeNull="true" /> <Column Name="EmployeeID" Type="System.Int32” DbType="Int" CanBeNull="true" /> <Column Name="FirstName" Type="System.String” DbType="NVarChar(50)" CanBeNull="true" /> <Column Name="LastName" Type="System.String" DbType="NVarChar(50)" CanBeNull="true" /> <Column Name="ManagerID" Type="System.Int32" DbType="Int" CanBeNull="true" /> <Column Name="ManagerFirstName" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> <Column Name="ManagerLastName" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" /> </ElementType></Function>
Содержание хранимой процедурыALTER PROCEDURE [dbo].[uspGetEmployeeManagers] @EmployeeID [int]ASBEGIN SET NOCOUNT ON;-- Use recursive query to list out all Employees required for a particular ManagerWITH [EMP_cte]([EmployeeID], [ManagerID], [FirstName], [LastName],[Title], [RecursionLevel])-- CTE name and columnsAS ( SELECT e.[EmployeeID], e.[ManagerID], c.[FirstName], c.[LastName], e.[Title], 0 -- Get the initial Employee FROM [HumanResources].[Employee] e INNER JOIN [Person].[Contact] c ON e.[ContactID] = c.[ContactID] WHERE e.[EmployeeID] = @EmployeeID UNION ALL
SELECT e.[EmployeeID], e.[ManagerID], c.[FirstName], c.[LastName], e.[Title], [RecursionLevel] + 1 -- Join recursive member to anchor FROM [HumanResources].[Employee] e INNER JOIN [EMP_cte] ON e.[EmployeeID] = [EMP_cte].[ManagerID] INNER JOIN [Person].[Contact] c ON e.[ContactID] = c.[ContactID] )
-- Join back to Employee to return the manager name SELECT [EMP_cte].[RecursionLevel], [EMP_cte].[EmployeeID], [EMP_cte].[FirstName], [EMP_cte].[LastName], [EMP_cte].[ManagerID], c.[FirstName] AS 'ManagerFirstName', c.[LastName] AS 'ManagerLastName' -- Outer select from the CTE FROM [EMP_cte] INNER JOIN [HumanResources].[Employee] e ON [EMP_cte].[ManagerID] = e.[EmployeeID] INNER JOIN [Person].[Contact] c ON e.[ContactID] = c.[ContactID] ORDER BY [RecursionLevel], [ManagerID], [EmployeeID] OPTION (MAXRECURSION 25)END;
ADO.NET Entity Framework• ADO.NET Entity Framework (EF) является более обширной технологией, чем Object Relation Mapping
(ORM). • Целью EF является выполнение более сложных задач, чем стандартное ORM. Она включает
концептуальную модель (conceptual model) как нечто конкретное, с помощью специальной среды (framework) для создания абстрактной модели на основе реляционной модели, тем самым решая задачу несоответствия между ними (impedance mismatch).
• Основным элементом EF является уровень абстракции, который разделен на концептуальный, согласующий (mapping) и логический уровни, которые составляют Entity Data Model (EDM).
• Кроме этого, EF включает:– два прикладных интерфейса APIs, – объектные сервисы (object services) и – клиента сущностей (entity client), для работы с EDM, – две конструкции для работы с данными:
• Entity SQL (ESQL) и • LINQ to Entities.
• Очень похожа на LINQ to SQL. Отличие:– может работать с разными реляционными БД;– в отличие от LINQ to SQL поддерживает не только прямое соответствие между классами и таблицами;– поддерживает наследие классов;– Для сложных приложений уровня Предприятия.
• Другие ORM технологии: NHibernate, EntitySpaces и LLBLGen Pro.
Создание EDM модели в проекте
• Добавить в проект новый элемент -«ADO.NET Entity Data Model»
• Работа с EDM: var departmentHistories = from dep in aw.EmployeeDepartmentHistory select dep; foreach (var edh in departmentHistories) { Console.WriteLine(edh.Employee.Contact.EmailAddress); }
• Модель сущностей данных - Entity Data Model (EDM) это спецификация для описания данных, которые используются приложениями разрабатываемыми с помощью Entity Framework.
• Модель EDM включает три уровня (структуры метаданных):– концептуальный уровень;– уровень согласования – логический уровень.
• Данные уровни (структуры) определяются, как схема проектирования (design schema, ваш .edmx файл) и включают следующие языки:
– Язык Описания Концептуальной Схемы (Conceptual Schema Definition Language, CSDL): Язык CSDL описывает концептуальную модель используемых в приложении данных (классов). Данная XML структура включает типы (сущности) используемые в программе и их отношения и описывает объектный код.
– Язык Описания Хранимых Схем (Stored Schema Definition Language, SSDL): Язык SSDL описывает структуру базы данных и данных, содержащихся в ней. Данная XML структура используется для описания логического уровня разрабатываемого приложения.
– Язык Описания Соответствия (Mapping Specification Language, MSL): Язык MSL является языком описания метаданных, которые задают соответствие концептуальной схемы, описанной на языке CSDL с логической моделью, описанной на языке SSDL. Данная XML структура является информацией, задающей соответствие (mapping information) между сущностями приложения с базой данных.
Приложение
База данных
Уровень Описания Хранимых Схем
Уровень Описания Соответствия
Уровень Описания Концептуальной схемыМодель сущностей данных - Entity Data Model (EDM)
ADO.NET Entity Framework