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

Лучший чат для C# программистов