Перейти к содержанию

Исходный код для примеров 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), окно которого показано ниже:

Первый экран мастера Entity Data Model Wizard

Сущностную модель данных можно создать с нуля или же сгенерировать ее на основе имеющейся базы данных. Здесь необходимо сгенерировать EDM из базы данных Northwind, поэтому выберите значок Generate from database (Создать из базы данных) и щелкните на кнопке Next (Далее) для перехода на экран подключения к данным:

Этот экран используется для выбора базы данных, на основе которой будет сгенерирована EDM-модель. На рисунке показано, что выбрана существующая база данных Northwind, которая ранее была подключена к SQL Server 2008.

Содержимое окна может отличаться в зависимости от местоположения базы данных. Выберите нужное соединение и щелкните на кнопке Next для перехода к следующему экрану мастера:

Экран объектов сущностной модели базы данных мастера Entity Data Model Wizard

На этом экране мастера выбираются таблицы, представления и хранимые процедуры из базы данных, которые будут включены в EDM-модель. Можно также выбрать множественную или единственную форму имен объектов (например, чтобы объекты, сгенерированные из таблицы Customers назывались Customer) и добавить внешние ключи.

Для текущих целей понадобится включить в модель все содержимое базы данных, поэтому отметьте все флажки на экране. Щелкните на кнопке Finish (Готово) для закрытия окна мастера и генерации модели. Когда процесс завершится, среда Visual Studio должна выглядеть примерно так:

EDM-модель Northwind в 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 закрывается.