Исходный код для примеров LINQ to Entities
LINQ --- LINQ to Entities --- Исходный код для примеров LINQ to Entities
Предварительные условия для запуска примеров
Поскольку почти во всех примерах, посвященных LINQ to Entities, используется расширенная база данных примеров Northwind, понадобятся сущностные классы и файлы отображения для базы данных Northwind.
Получение соответствующей версии базы данных Northwind и создание подключения
Данная подтема подробно расписана в статье Исходный код для примеров LINQ to SQL и здесь ничем не отличается.
Генерация сущностной модели данных Northwind
Сгенерировать модель EDM можно либо с помощью инструмента командной строки EdmGen, либо в среде Visual Studio 2010. Далее будет показано, как это делать с использованием графического мастера Visual Studio.
Сначала щелкните правой кнопкой мыши на проекте, выберите в контекстном меню пункт Add --> New Item (Добавить --> Новый элемент) и затем укажите в списке вариант ADO.NET Entity Data Model (Модель ADO.NET EDM). Измените имя модели данных. Поскольку используется база данных Northwind, в качестве имени имеет смысл указать NorthwindDataModel.edmx. Щелкните на кнопке Add (Добавить), после чего запустится мастер создания сущностной модели данных (Entity Data Model Wizard), окно которого показано ниже:
Сущностную модель данных можно создать с нуля или же сгенерировать ее на основе имеющейся базы данных. Здесь необходимо сгенерировать EDM из базы данных Northwind, поэтому выберите значок Generate from database (Создать из базы данных) и щелкните на кнопке Next (Далее) для перехода на экран подключения к данным:
Этот экран используется для выбора базы данных, на основе которой будет сгенерирована EDM-модель. На рисунке показано, что выбрана существующая база данных Northwind, которая ранее была подключена к SQL Server 2008.
Содержимое окна может отличаться в зависимости от местоположения базы данных. Выберите нужное соединение и щелкните на кнопке Next для перехода к следующему экрану мастера:
На этом экране мастера выбираются таблицы, представления и хранимые процедуры из базы данных, которые будут включены в EDM-модель. Можно также выбрать множественную или единственную форму имен объектов (например, чтобы объекты, сгенерированные из таблицы Customers назывались Customer) и добавить внешние ключи.
Для текущих целей понадобится включить в модель все содержимое базы данных, поэтому отметьте все флажки на экране. Щелкните на кнопке Finish (Готово) для закрытия окна мастера и генерации модели. Когда процесс завершится, среда Visual Studio должна выглядеть примерно так:
В основной части окна показана создаваемая сущностная модель. Здесь можно видеть свойства каждого сущностного класса и отношения между ними. Кроме того, также выводится множество предупреждений относительно модели данных; они вызваны тем, что с расширенной базой данных Northwind связан ряд недостатков. Пока эти ошибки игнорируются, но в реальном проекте они должны быть тщательно изучены.
Наконец, обратите внимание, что мастер создания EDM добавил в проект ряд новых ссылок; они требуются для API-интерфейса Entity Framework и не должны удаляться. На этом все — сущностная модель данных для расширенной базы данных Northwind сгенерирована. В следующем разделе будет приведен очень краткий обзор ее использования.
Использование API-интерфейса LINQ to Entities
Сборки, которые понадобятся для использования LINQ to Entities, добавляются к проекту автоматически при генерации сущностной модели данных. В отличие от LINQ to SQL, импортировать пространство имен для использования сущностных классов не понадобится, т.к. мастер Entity Data Model генерирует сущностные модели данных в пространстве имен по умолчанию проекта.
IQueryable<T>
Во многих примерах, посвященных LINQ to Entities, работа будет проводиться с последовательностями типа IQueryable<T>, где T — тип сущностного класса. Этот тип последовательностей обычно возвращается запросами LINQ to Entities, как и в LINQ to SQL. Обычно работа с ними выглядит, как с последовательностью IEnumerable<T>, и это не случайно. Интерфейс IQueryable<T> реализует интерфейс IEnumerable<T>. Ниже приведено определение IQueryable<T>:
interface IQueryable<T> : IEnumerable<T>, IQueryable
Благодаря этому наследованию последовательность IQueryable<T> можно трактовать как последовательность IEnumerable<T>.
Некоторые общие методы
В процессе демонстрации средств LINQ to Entities нужна возможность запрашивать или модифицировать базу данных, внешнюю по отношению к Entity Framework. Чтобы выделить код LINQ to Entities и исключить как можно больше тривиальных деталей (в то же время обеспечивая полезные примеры), были разработаны некоторые общие методы. Добавьте их к своему исходному коду при тестировании примеров:
- GetStringFromDb()
Общий метод, который весьма пригодится — это метод для получения простой строки из базы данных с помощью стандартного механизма ADO.NET. Это позволит посмотреть, что на самом деле есть в базе данных, и сравнить с тем, что отображает LINQ to Entities:
static private string GetStringFromDb(string sqlQuery) { string connection = (@"Data Source=MICROSOF-1EA29E\SQLEXPRESS;Initial Catalog=C:\NORTHWIND.MDF;Integrated Security=True"); System.Data.SqlClient.SqlConnection sqlConn = new System.Data.SqlClient.SqlConnection(connection); if (sqlConn.State != ConnectionState.Open) { sqlConn.Open(); } System.Data.SqlClient.SqlCommand sqlCommand = new System.Data.SqlClient.SqlCommand(sqlQuery, sqlConn); System.Data.SqlClient.SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(); string result = null; try { if (!sqlDataReader.Read()) { throw (new Exception( String.Format("Unexpected exception executing query [{0}].", sqlQuery))); } else { if (!sqlDataReader.IsDBNull(0)) { result = sqlDataReader.GetString(0); } } } finally { // Всегда вызывать Close, когда чтение завершено sqlDataReader.Close(); sqlConn.Close(); } return (result); }
При вызове методу GetStringFromDb передается строка запроса SQL. Метод создает и открывает новое соединение с базой данных.
Затем создается объект SqlCommand, конструктору которого передается запрос и соединение. Затем SqlDataReader получается вызовом метода ExecuteReader на SqlCommand. Объект SqlDataReader читает данные с помощью своего метода Read, и если данные были прочитаны, а значение возвращенного первого столбца не null, то это значение извлекается методом GetString. Наконец, SqlDataReader и SqlConnection закрываются, и значение первого столбца возвращается вызывающему методу.
- ExecuteStatementInDb()
Иногда для изменения состояния базы данных вне Entity Framework возникает необходимость в выполнении оператора SQL, отличного от запроса вроде insert, update и delete в ADO.NET. Для этой цели был создан метод ExecuteStatementInDb:
static private void ExecuteStatementInDb(string cmd) { // Здесь укажите свою строку подключения string connection = (@"Data Source=MICROSOF-1EA29E\SQLEXPRESS; Initial Catalog=C:\NORTHWIND.MDF;Integrated Security=True"); System.Data.SqlClient.SqlConnection sqlConn = new System.Data.SqlClient.SqlConnection(connection); System.Data.SqlClient.SqlCommand sqlComm = new System.Data.SqlClient.SqlCommand(cmd); sqlComm.Connection = sqlConn; try { sqlConn.Open(); Console.WriteLine("Выполнение оператора SQL для базы данных с помощью ADO.NET ..."); sqlComm.ExecuteNonQuery(); Console.WriteLine("Database updated."); } finally { // Закрыть соединение sqlComm.Connection.Close(); } }
При вызове методу ExecuteStatementInDb передается аргумент string, содержащий команду SQL. Создается экземпляр SqlConnection, за которым следует SqlCommand. Объект SqlConnection затем открывается и команда SQL выполняется посредством вызова метода ExecuteNonQuery объекта SqlCommand. Наконец, SqlCommand закрывается.