Модель EDM

Понимая предназначение платформы ADO.NET Entity Framewrok, а также имея общее представление о ее работе, можно приступать к рассмотрению первого примера. Чтобы пока не усложнять картину, построим модель EDM, которая обеспечит доступ только к таблице Inventory базы данных AutoLot, созданной ранее — ADO_NET/base/level3/3_2.php. Разобравшись с основами, мы затем построим новую модель EDM, которая будет рассчитана на всю базу данных AutoLot.
Генерация файла *.edmx
Начнем с создания консольного приложения. Когда планируется использование Entity Framework, первый шаг состоит в генерации необходимой концептуальной, логической и физической модели данных, определенной в файле *.edmx. Один из способов предусматривает применение для этого утилиты командной строки EdmGen.exe из комплекта .NET 4.0 SDK. Откройте окно командной строки Visual Studio 2010 и введите следующую команду:
На консоль выводится список опций, которые можно указывать утилите для генерации необходимых файлов, основываясь на существующей базе данных; кроме того, доступны опции для генерации совершенно новой базы данных на основе имеющихся сущностных файлов. Ниже описаны некоторые общие опции EdmGen.exe:
/mode:FullGeneration
Генерировать файлы *.ssdl, *.msl, *.csdl и клиентские сущности из указанной базы данных
/project:
Базовое имя, которое должно использоваться для сгенерированного кода и файлов. Обычно это имя базы данных, из которой извлекается информация (допускается сокращенная форма — /р:)
/connectionstring:
Строка соединения, используемая для взаимодействия с базой данных (допускается сокращенная форма — /с:)
/language:
Позволяет указать, какой синтаксис должен использоваться для сгенерированного кода — C# или VB
/pluralize
Позволяет автоматически выбирать множественное или единственное число для имени набора сущностей, имени типа сущности и имени навигационного свойства, согласно правилам английского языка
Как и платформа .NET 4.0 в целом, программная модель EF поддерживает программирование в стиле сначала домен, что позволяет создавать свойства (с применением типичных объектно-ориентированных приемов) и использовать их для генерации новой базы данных. В этом вводном обзоре ADO.NET EF ни подход «сначала модель», ни генерация сущностной модели клиентской стороны с помощью утилиты EdmGen.exe применяться не будут. Вместо этого будут использоваться визуальные конструкторы EDM из среды Visual Studio 2010.
Выберите пункт меню Project —> Add New Item (Проект —> Добавить новый элемент) и вставьте новый элемент ADO.NET Entity Data Model по имени InventoryEDM.edmx:

Щелчок на кнопке Add (Добавить) приводит к запуску мастера создания модели сущностных данных (Entity Data Model Wizard). На первом шаге мастер позволяет выбрать, нужно генерировать EDM из существующей базы данных либо определить пустую модель (для разработки в стиле «сначала модель»). Выберите опцию Generate from database (Генерировать из базы данных) и щелкните на кнопке Next (Далее).
На втором шаге мастера выбирается база данных. Если соединение с базой данных внутри проводника сервера Visual Studio 2010 уже существует, оно будет присутствовать в раскрывающемся списке. Если же нет, щелкните на кнопке New Connection (Создать соединение). В любом случае выберите базу данных AutoLot и отметьте флажок Save entity connection settings in App.config as (Сохранить настройки соединения в файле App.config как):

Прежде чем щелкать на кнопке Next, взгляните на формат строки соединения:
Основной интерес в ней представляет флаг metadata, который используется для указания имен встроенных данных XML-ресурсов концептуального, физического и файла отображений (вспомните, что во время компиляции файл *.edmx будет разделен на отдельные файлы, и данные этих файлов примут вид двоичных ресурсов, встраиваемых в сборку).
На последнем шаге мастера можно выбрать элементы из базы данных, для которой необходимо сгенерировать модель EDM. В рассматриваемом примере ограничимся только таблицей Inventory. Щелкните на кнопке Finish для генерации модели EDM.
Изменение формы сущностных данных
После завершения работы с мастером откроется визуальный конструктор EDM в IDE-среде с одной сущностью по имени Inventory. Просмотреть композицию любой сущности в визуальном конструкторе можно в окне Model Browser (Браузер моделей), которое открывается через пункт меню View —> Other Windows (Вид —> Другие окна).
Теперь взгляните на формат концептуальной модели для таблицы базы данных Inventory, представленный в папке Entity Types (Типы сущности). В узле хранилища, имя которого совпадает с именем базы данных (AutoLotModel.Store), находится физическая модель базы данных:

По умолчанию имена сущностей будут основаны на именах исходных объектов баз данных; однако, вспомните, что имена сущностей в концептуальной модели могут быть любыми. Чтобы изменить имя сущности либо имена свойств сущности, необходимо выбрать нужный элемент в визуальном конструкторе и установить соответствующим образом свойство Name в окне свойств (Properties). Переименуйте сущность Inventory в Car и свойство PetName в CarNickname:

Теперь выберите сущность Car в визуальном конструкторе и снова загляните в окно Properties. Вы должны увидеть поле Entity Set Name (Имя набора сущностей), также переименованное из Inventories в Cars. Значение Entity Set Name важно, потому что оно соответствует имени свойства в классе контекста данных, который используется для модификации базы данных. Вспомните, что это свойство инкапсулирует переменную-член ObjectSet<T> класса-наследника ObjectContext.
Прежде чем двигаться дальше, скомпилируйте приложение; это приведет к обновлению кодовой базы и генерации файлов *.csdl, *.msl и *.ssdl на основе данных файла *.edmx.
Просмотр отображений
Имея данные в измененной форме, можно просматривать отображения между концептуальным уровнем и физическим уровнем в окне Mapping Details (Сведения об отображениях), которое открывается через пункт меню View —> Other Windows —> Mapping Details. Взгляните на рисунок ниже и обратите внимание, что узлы в левой части дерева представляют имена данных из физического уровня, в то время как узлы справа представляют имена концептуальной модели:

Просмотр данных сгенерированного файла *.edmx
Теперь давайте посмотрим, что именно мастер EDM Wizard сгенерировал. Щелкните правой кнопкой мыши на файле InventoryEDM.edmx в проводнике решения и выберите в контекстном меню пункт Open With. (Открыть с помощью). В открывшемся диалоговом окне выберите опцию XML Editor (Редактор XML). Это позволит просмотреть XML-данные, лежащие в основе представления в визуальном конструкторе EDM. Структура этого XML-документа разделена на четыре части: все они находятся в корневом элементе <edms:Edmx>.
Подэлемент <edmx:Runtime> определяет XML-данные для концептуальной, физической и модели уровня отображения. Ниже показано определение физической таблицы базы данных Inventory:
Обратите внимание, что узел <Schema> определяет имя поставщика данных ADO.NET, который использует эту информацию при взаимодействии с базой данных (System.Data.SqlClient). Узлами <EntityType> помечается имя физической таблицы базы данных, а также каждый столбец в таблице.
Следующая важная часть файла *.edmx — элемент <edmx:ConceptualModels>. который определяет измененные сущности клиентской стороны. Как видно, сущность Cars определяет свойство CarNickname, которое изменяется в визуальном конструкторе:
Это перемещает на уровень отображения, который окно Mapping Details и исполняющая среда EF используют для подключения имен в концептуальной модели к физической модели:
Последней частью файла *.edmx является элемент <Designer>. который исполняющей средой EF не используется. Он содержит инструкции, используемые Visual Studio для отображения сущностей на поверхности визуального конструктора.
Удостоверьтесь, что проект скомпилирован, по крайней мере, однажды, и щелкните на кнопке Show All Files (Показать все файлы) в проводнике решений. Затем зайдите в папку obj\Debug, а после этого — в edmxResourcesToEmbed. Здесь находятся три XML-файла, основанные на содержимом файла *.edmx:

Данные в этих файлах будут встроены в сборку как двоичные ресурсы. Таким образом, приложение .NET обладает всей информацией, необходимой для понимания концептуального, физического и уровня отображения модели EDM.
Creating an Entity Data Model
Here, we are going to create an Entity Data Model (EDM) for an existing database in database-first approach and understand the basic building blocks.
Entity Framework uses EDM for all the database-related operations. Entity Data Model is a model that describes entities and the relationships between them. Let's create a simple EDM for the School database using Visual Studio (2012\2015\2017) and Entity Framework 6.
1. Open Visual Studio and create a console project.
Go to PROJECT menu ->
2. Now, add Entity Data Model by right clicking on the project in the solution explorer -> Add -> New Item. This will open the Add New Item popup. In the popup, select ADO.NET Entity Data Model and provide an appropriate name to the EDM ('School' in this case) and click the Add button.
3. Entity Data Model Wizard in Visual Studio (2012/2015/2017) opens with four options to select from: EF Designer from database for the database-first approach, Empty EF Designer model for the model-first approach, Empty Code First model and Code First from database for Code-First approach. We are using database-first approach here, so select the EF Designer from database option and click Next.
4. In this step, you need to create a connection with your existing database. If this is the first time you are creating an EDM for your database, then you need to create a new connection by clicking on the New Connection. button.
In the Connection Properties popup, provide the server name (. for the local database) and select your database name and click the OK button.
This will add a connection string to your app.config file with the <DB name>Entities name. Click Next after you set up your DB connection.
5. In this step, you need to choose the version of Entity Framework. We will use Entity Framework 6.0 in the basic tutorials so select Entity Framework 6.0 and click Next.
Note: If you already have installed the latest version of Entity Framework using NuGet manager, then this step of the wizard will no longer appear.
6. Next step will display all the Tables, Views and Stored Procedures (SP) in the database. Select the Tables, Views and SPs you want, keep the default checkboxes selected and click Finish. You can change the Model Namespace if you want.
Note:
Pluralize or singularize generated object names checkbox singularizes an entityset name, if the table name in the database is plural. For example, if the SchoolDB database contains the Students table name, then entity set would be singular Student . Similarly, relationships between the models will be pluralized if the table has a one-to-many or a many-to-many relationship with other tables. For example, the Student table has many-to-many relationship with Course table, so the Student entity set will have plural name Courses for the collection navigation property of Course type.
The second checkbox, Include foreign key columns in the model, includes a foreign key property explicitly to represent the foreign key. For example, the Student table has a one-to-many relationship with the Standard table. To represent this in the model, the Student entityset includes a StandardId property with Standard reference navigation property. If this checkbox is unchecked, then it will only include the Standard reference navigation property, but not the StandardId .
The third checkbox, Import selected stored procedures and functions into entity model, automatically creates Function Imports for the stored procedures and functions. You don't need to import functions manually, like it was necessary prior to Entity Framework 6.0.
7. After clicking on Finish, a School.edmx file will be added into your project.
Open EDM designer by double clicking on School.edmx. This displays all the entities for the selected tables and the relationships between them, as shown below:
EDM adds the provider and connection string settings in the App.config file, as shown below:
Thus, you can create an Entity Data Model file (.edmx) for your existing database.
You can open an EDM designer in XML view where you can see all the three parts of the EDM: Conceptual schema (CSDL), Storage schema (SSDL) and mapping schema (MSL), together in XML view.
Right click on School.edmx -> click 'Open with..', this will open a popup window.
Select 'XML (text) Editor' in the popup window.
Visual Studio cannot display the model in Design view and in XML format at the same time, so you will see a message asking whether it's OK to close the Design view of the model, click Yes. This will open the XML format view. You can see the following XML view by toggling all outlining as shown below.
You can see the SSDL content, the CSDL content and the C-S mapping content here. If you expand the SSDL and CSDL, each one has some common XML node under each schema node. You don't need to edit the xml data because this can be accomplished easier in the Model Browser.
Now, let's examine all the building blocks of the generated EDM (School.edmx) as shown in the above figure.
Entity-Table Mapping
Each entity in EDM is mapped with the database table. You can check the entity-table mapping by right clicking on any entity in the EDM designer -> select Table Mapping. Also, if you change any property name of the entity from designer then the table mapping would reflect that change automatically.
Context & Entity Classes
Every Entity Data Model generates a context and an entity class for each database table. Expand the .edmx file in the solution explorer and open two important files, <EDM Name>.Context.tt and <EDM Name>.tt , as shown below:
School.Context.tt: This T4 template file generates a context class whenever you change the Entity Data Model (.edmx file). You can see the context class file by expanding School.Context.tt . The context class resides in the <EDM Name>.context.cs file. The default context class name is <DB Name>Entities . For example, the context class name for SchoolDB is SchoolDBEntities and derived from the DBContext class.
School.tt: School.tt is a T4 template file that generates entity classes for each DB table. Entity classes are POCO (Plain Old CLR Object) classes. The following code snippet shows the Student entity.
Learn how to see all the objects of EDM using the Model Browser in the next section.
Модель ado net edm как добавить в vs
![]()
This forum has migrated to Microsoft Q&A. Visit Microsoft Q&A to post new questions.
Asked by:
Question
All replies
Please open VS installer and confirm the component "Entity Framework 6 tools" has been installed?
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.
- Edited by Kyle Wang — MSFT Microsoft contingent staff Tuesday, September 24, 2019 2:49 AM
- Proposed as answer by Saleem Yusuf Sunday, January 12, 2020 11:24 PM
I have Entity Framework 6 Tools enabled in VS2019 Community Edition — but still no ADO.NET or any other SQL or other data connection choices in the Visual C#/data section; I used the installer to upgrade today to the latest release.
All I get is three choices for adding a new item in data:
JSON Schema File
So cannot install a database connection to include database in project — help urgently pls!
I have Entity Framework 6 Tools enabled in VS2019 Community Edition — but still no ADO.NET or any other SQL or other data connection choices in the Visual C#/data section; I used the installer to upgrade today to the latest release.
All I get is three choices for adding a new item in data:
JSON File
JSON Schema File
XML File
So cannot install a database connection to include database in project — help urgently pls!
I didn’t do anything special in installing VS2019 Community. Maybe the install on your machine is bad.
Oh, I just realised where is the problem!
I had the same thing, couldn’t find ADO.NET entity data model!
However what we probably have in common is that we opened "windows desktop app" instead of "windows form app"!
So after I opened new windows form app the ADO.NET entity data model appeared!
Hope this helps!
- Proposed as answer by AQEELA UROOJ Sunday, January 12, 2020 6:09 PM
I had the same problem when tried to create a model under App_Data.
However, when I try the same under the project I get the option!
- Proposed as answer by Saleem Yusuf Sunday, January 12, 2020 11:25 PM
I had the same issue, ADO.NET Entity Data Model would not show in a Console .NET Core project. I then delete this project and created a Console .NET Framework project and now I see ADO.NET Entity Data Model plus 8 other template. I have Visual Studio 2019 Enterprise.
M. Saleem Yusuf
EF Core uses Dbcontext scaffolding from the .NET Core Command Prompt or through the Nuget Package Manager Console. So there is no ADO.NET Entity Data Model that is ever going to show in Visual Stuido for a Core project of any type that will implement the ADO.NET Core Entity Framework based on model creation.
- Proposed as answer by Saleem Yusuf Sunday, January 12, 2020 11:25 PM
- Proposed as answer by Misaghfar Saturday, March 21, 2020 12:25 PM
I had same problem and I just stumbled upon this post. Just wanted to share my two cents. I guess it’s something to do with way how .net standard library has been implemented instead of earlier Base class library. So For example when you look at class library(.net standard) that is referencing by default to SDK. So template available for these project is different. Ado.net as template is not available to class library project but is there let’s say for WebApi projects. Take a class library or project that refer to .net framework and you should be fine. Choose first Class lib and you will see Ado.net chosse second option and you don’t see it
- Edited by Rohit Sakalle Sunday, March 29, 2020 3:26 PM
- Proposed as answer by Rohit Sakalle Sunday, March 29, 2020 3:27 PM
One can install the PowerTools that has Reverse Engineering graphical interface that can be pointed at an existing database and select the tables to build the EF Model with a Visual Stuido project.
Создание приложений для СУБД Firebird с использованием различных компонент и драйверов: ADO.NET Entity Framework 6
В данной статье будет описан процесс создания приложений для СУБД Firebird с использованием компонентов доступа Entity Framework и среды Visual Studio 2015.
ADO.NET Entity Framework (EF) — объектно-ориентированная технология доступа к данным, является object-relational mapping (ORM) решением для .NET Framework от Microsoft. Предоставляет возможность взаимодействия с объектами как посредством LINQ в виде LINQ to Entities, так и с использованием Entity SQL.
- Database first: Entity Framework создаёт набор классов, которые отражают модель конкретной базы данных.
- Model first: сначала разработчик создаёт модель базы данных, по которой затем Entity Framework создаёт реальную базу данных на сервере.
- Code first: разработчик создаёт класс модели данных, которые будут храниться в БД, а затем Entity Framework по этой модели генерирует базу данных и её таблицы
В своём приложении мы будем использовать подход Code First, однако вы без труда сможете использовать и другие подходы.
Наше приложение будет работать с базой данных, модель которой представлена на рисунке ниже.

Подготовка Visual Studio 2015 для работы с Firebird
- FirebirdSql.Data.FirebirdClient.dll
- EntityFramework.Firebird.dll
- DDEX Provider for Visual Studio
Установка первых двух не вызывает никаких сложностей. В настоящий момент они распространяются и устанавливаются в проект с помощью NuGet. А вот последняя библиотека, предназначенная для работы мастеров Visual Studio, устанавливается не так легко и может потратить у вас много сил и времени.
Далее описан процесс установки:
В глобальном кэше сборок содержатся следующие сборки:
FirebirdSql.Data.FirebirdClient, Version=4.10.0.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c, processorArchitecture=MSIL
Для проверки, что всё успешно установилось, запускаем Visual Studio 2015. Находим обозреватель серверов и пытаемся подключиться к одной из существующих баз данных Firebird.




Создание проекта
В данной статье мы рассмотрим пример создания Windows Forms приложения. Остальные типы приложений хоть и отличаются, но принципы работы с Firebird через Entity Framework остаются те же.
- FirebirdSql.Data.FirebirdClient
- EntityFramework
- EntityFramework.Firebird
Для этого необходимо щёлкнуть правой клавишей мыши по имени проекта в обозревателе решений и в выпадающем меню выбрать пункт «Управление пакетами NuGet».

В появившемся менеджере пакетов произвести поиск и установку необходимых пакетов.

Создание EDM модели
В своём приложении мы будем использовать подход Code First.
Для создания модели EDM необходимо щёлкнуть правой клавишей мыши по имени проекта в обозревателе решений и выбрать пункт меню Добавить -> Создать элемент.

Далее в мастере добавления нового элемента выбираем пункт «Модель ADO.NET EDM».

Поскольку у нас уже существует база данных (см. Создание приложений для СУБД Firebird с использованием различных компонент и драйверов: FireDac), то будем генерировать EDM модель из базы данных.

Теперь надо выбрать подключение, из которого будет создана модель. Если Такого подключения нет, то его надо создать.


Кроме основных параметров подключения могут потребоваться также указать ряд дополнительных параметров, например, уровень изолированности транзакций (по умолчанию Read Commited), использование пула подключений и т.д.

В процессе работы мастера создания модели у вас спросят, как хранить строку подключения.

Если вы строите веб приложение или трёхзвенку, где все пользователи будут работать с базой данных под одной и той же учётной записью, то смело выбирайте «Да». Если же ваше приложение должно запрашивать учётные данные для соединения с базой данных выбирайте «Нет». Впрочем, с мастерами гораздо более удобно работать, когда у вас выбран пункт «Да». Вы всегда можете это изменить в готовом приложении, просто отредактировав строку подключения в файле конфигурации приложения .exe.conf. Строка подключения будет сохранена в секции connectionStrings примерно в таком виде
Для того чтобы файл конфигурации перестал хранить конфиденциальную информацию просто удалите из строки подключения
Далее у вас спросят, какие таблицы и представления должны быть включены модель.

В принципе EDM модель готова. После работы этого мастера у вас должно появиться 5 новых файлов. Один файл модели и четыре файла описывающих каждую из сущностей модели.
Давайте посмотрим один из сгенерированных файлов описывающих сущность INVOICE.
Класс содержат свойства, которые отображают поля таблицы INVOICE. Каждое из таких свойств снабжено атрибутами, описывающими ограничения. Подробнее об различных атрибутах вы можете почитать в документации Майкрософт Code First Data Annotations.
Кроме того, было сгенерировано ещё два навигационных свойства CUSTOMER и INVOICE_LINES. Первое содержит ссылку на сущность поставщика, второе – коллекцию строк накладных. Оно было сгенерировано потому, что таблица INVOICE_LINE имеет внешний ключ на таблицу INVOICE. Конечно, вы можете удалить это свойство из сущности INVOICE, но делать это вовсе не обязательно. Дело в том, что в данном случае свойства CUSTOMER и INVOICE_LINES использует так называемую «ленивую загрузку». При таком загрузка осуществляется при первом обращении к объекту, т.е. если связанные данные не нужны, то они не подгружаются. Однако при первом же обращении к навигационному свойству эти данные автоматически подгружаются из БД.
При использовании ленивой загрузки надо иметь в виду некоторые моменты при объявлении классов. Так, классы, использующие ленивую загрузку должны быть публичными, а их свойства должны иметь модификаторы public и virtual.
В этом же классе нас ожидает первый неприятный сюрприз. Поле TOTAL_SALE было отображено в сущности как double, хотя в базе данных оно имеет тип NUMERIC(15, 2), таким образом, мы имеем потерю точности. Я склонен расценивать это как баг в Firebird ADO.NET Provider. Давайте попробуем исправить эту досадную оплошность. В C# существует тип decimal для операций над числами с фиксированной точностью.
Кроме того, изменим описание всех полей во всех сущностях, где используется тип Firebird NUMERIC(x, y). А именно PRODUCT.PRICE, INVOICE_LINE.QUANTITY, INVOICE_LINE.SALE_PRICE.
Теперь откроем файл DbModel.cs описывающий модель в целом.
Здесь мы видим свойства описывающие набор данных для каждой сущности. А так же задание дополнительных свойств создания модели с помощью Fluent API. Полное описание Fluent API вы может прочитать в документации Microsoft Configuring/Mapping Properties and Types with the Fluent API.
Зададим в методе OnModelCreating точность для свойств типа decimal с помощью Fluent API. Для этого допишем следующие строчки
Создание пользовательского интерфейса
В нашем приложении мы создадим два справочника: справочник товаров и справочник заказчиков. Каждый справочник содержит сетку DataGridView, панель с кнопками ToolStrip, а также компонент BindingSource, который служит для упрощения привязки данных к элементам управления в форме.

Поскольку по функционалу оба справочника похожи и реализованы схожим образом описывать мы будем только один.
Получение контекста
Для работы с нашей моделью нам потребуется метод для получения контекста (или модели). В принципе для этого достаточно выполнить:
Однако, если в строке подключения не хранятся конфиденциальные данные (например, пароль), а мы инициализируем во время авторизации их при старте приложения, то нам потребуется специальный метод для хранения и восстановления строки подключения или сохранение ранее созданного контекста. Для этого создадим специальный класс, который помимо метода для получения контекста будет также содержать некоторые глобальные переменные уровня приложения, например рабочий период.
Сама строка подключения инициализируется при старте приложения, после того как успешно прошла авторизация. Для этого в обработчике события Load главной формы напишем следующий код.
Теперь для получения контекста мы будем использовать статический метод CreateDbContext.
Работа с данными
Сами по себе сущности модели не содержат никаких данных. Самым простым способом загрузить данные является вызовам метода Load, например вот так:
- Метод Load загружает сразу все данные из таблицы CUSTOMER в память.
- Ленивые свойства (INVOICES) хоть и не загружаются сразу, а лишь по мере обращения к ним, всё равно будут загружены при отображении записей в гриде. Причём ровно столько раз, сколько записей будет выведено.
- Порядок записей неопределён.
Методы расширений LINQ могут возвращать два объекта: IEnumerable и IQueryable. Интерфейс IQueryable наследуется от IEnumerable, поэтому по идее объект IQueryable это и есть также объект IEnumerable. Но между ними есть существенная разница.
Интерфейс IEnumerable находится в пространстве имён System.Collections. Объект IEnumerable представляет набор данных в памяти и может перемещаться по этим данным только вперёд. При выполнении запроса IEnumerable загружает все данные, и если нам надо выполнить их фильтрацию, то сама фильтрация происходит на стороне клиента.
Интерфейс IQueryable располагается в пространстве имён System.Linq. Объект IQueryable предоставляет удалённый доступ к базе данных и позволяет перемещаться по данным как в прямом порядке от начала до конца, так и в обратном порядке. В процессе создания запроса, возвращаемым объектом которого является IQueryable, происходит оптимизация запроса. В итоге в процессе его выполнения тратится меньше памяти, меньше пропускной способности сети.
Свойство Local возвращает интерфейс IEnumerable. Поэтому мы можем составлять LINQ запросы к нему.
Однако как уже сказано этот запрос будет выполняться над данными в памяти. В принципе для маленьких таблиц, которым не требуется предварительная фильтрация это приемлемо.
Для того чтобы LINQ запрос был преобразован в SQL и выполнялся на стороне сервера нам необходимо использовать в LINQ запросе вместо обращения к свойству dbContext.CUSTOMERS.Local обращаться сразу к dbContext.CUSTOMERS. В этом случае нам не потребуется предварительный вызов dbContext.CUSTOMERS.Load();
для загрузки коллекции в память.
Однако тут нас подстерегает одна маленькая засада. Объекты IQueryable не умеют возвращать BindingList. BindingList является базовым классом для создания двустороннего механизма привязки данных. Из интерфейса IQueryable мы можем получить обычный список посредством вызова ToList, но в этом случае мы лишаемся приятных бонусов, таких как сортировка в гриде и многих других. Кстати в .NET Framework 5 это уже исправили и создали специальное расширение. Сделаем своё расширение, которое будет делать тоже самое.
В этом же классе присутствует ещё несколько расширений.
Метод NextValueFor предназначен для получения следующего значения генератора. Метод dbContext.Database.SqlQuery позволяет выполнять SQL запросы напрямую и отображать их результаты на некоторую сущность (проекцию). Вы можете воспользоваться им, если вам потребуется выполнить SQL запрос напрямую.
Метод DetachAll предназначен для отсоединения всех объектов коллекции DBSet от контекста. Это необходимо для обновления внутреннего кеша. Дело в том, что в рамках контекста все извлекаемые кешируются и не извлекаются из базы данных снова. Однако это не всегда полезно, поскольку затрудняет получение изменённых записей сделанных в другом контексте.
Метод Refresh предназначен для обновления свойств объекта-сущности. Он полезен для обновления свойств объекта после его редактирования или добавления.
Таким образом, наш код загрузки данных будет выглядеть так
Код обработчика события на нажатие кнопки добавления выглядит следующим образом.
При добавлении новой записи мы получаем значение следующего идентификатора с помощью генератора. Мы могли бы не инициализировать значение идентификатора, и в этом случае отработал бы BEFORE INSERT триггер, который всё равно дёрнул бы следующее значение генератора. Однако в этом случае мы не смогли бы обновить вновь добавленную запись.
Код обработчика события на нажатие кнопки редактирования выглядит следующим образом.
Форма для редактирования заказчика выглядит следующим образом.

Код привязки к данным очень прост.
Код обработчика события на нажатие кнопки удаления выглядит следующим образом.
Журналы
В нашем приложении будет один журнал «Счёт-фактуры». В отличие от справочников журналы содержат довольно большое количество записей и являются часто пополняемыми.
Счёт-фактура – состоит из заголовка, где описываются общие атрибуты (номер, дата, заказчик …), и строк счёт-фактуры со списком товаром, их количеством, стоимостью и т.д. Для таких документов удобно иметь два грида: в главном отображаются данные о шапке документа, а в детализирующем — список товаров. Таким образом, на форму документа нам потребуется поместить два компонента DataGridView, к каждому из которых привязать свой BindingSource

Большинство журналов содержат поле с датой создания документа. Чтобы уменьшить количество выбираемых данных обычно принято вводить такое понятие как рабочий период для того, чтобы уменьшить объём данных передаваемый на клиента. Рабочий период – это диапазон дат, внутри которого требуются рабочие документы. Поскольку приложение может содержать более одного журнала, то имеет смысл разместить переменные, содержащие дату начала и окончания рабочего периода, в глобальном модуле AppVariables (см. Получение контекста), который, так или иначе, используется всеми модулями, работающими с БД. При старте приложения рабочий период обычно инициализируется датой начала и окончания текущего квартала (могут быть другие варианты). В ходе работы приложения можно изменить рабочий период по желанию пользователя.
Поскольку чаще всего требуются именно последние введённые документы, то имеет смысл сортировать их по дате в обратном порядке. Извлекать данные, как и в случае со справочниками будем при помощи LINQ. С учётом вышесказанного, метод для загрузки данных шапок счёт-фактур будет выглядеть следующим образом:
В качестве проекции мы использовали не анонимный тип, а класс InvoiceView. Это упрощает приведение типа. Определение класса InvoiceView выглядит следующим образом:
Метод Load позволяет нам быстро обновить 1 добавленную или обновлённую запись в гриде, вместо того чтобы полностью перезагружать все записи.
Код обработчика события на нажатие кнопки добавления выглядит следующим образом.
В отличие от аналогичного метода справочника здесь обновление записи происходит не с помощью вызова dbContext.Refresh, а с помощью метода Load проекции InvoiceView. Дело в том, что dbContext.Refresh предназначен для обновления объектов сущностей, а не произвольных проекций, которые могут получаться сложными LINQ запросами.
Код обработчика события на нажатие кнопки редактирования выглядит следующим образом.
Здесь нам потребовалось найти сущность по её идентификатору доступному в текущей записи. Свойство CurrentInvoice предназначено для получения выделенной в гриде счёт-фактуры. Оно реализовано так:
Удаление шапки счёт фактуры вы можете сделать самостоятельно.
Помимо добавления, редактирования и удаления для счёт-фактур мы ввели ещё одну операцию оплаты, код метода реализующего эту операцию выглядит следующим образом:
- Получать данные по каждой счёт-фактуре из навигационного свойства INVOICE_LINE и отображать содержимое этого сложного свойства (возможно с преобразованиями LINQ) в детейл гриде.
- Получать данные по каждой счёт-фактуре отдельным LINQ запросом, который будет перевыполняться при перемещении в указателя в мастер гриде.
Каждый из методов имеет свои преимущества и недостатки.
Первый метод предполагает, что при открытии формы счёт-фактуры мы должны сразу извлечь все счёт-фактуры за указанный период и связанные данные по их позициям. Это хоть и выполняется одним SQL запросом, но может занять довольно много времени, и требует значительного объёма оперативной памяти. Этот метод лучше подходит для WEB приложений где вывод записей обычно происходит постранично.
Второй метод несколько более сложен в реализации, но позволяет быстро открывать форму счёт-фактуры и менее требователен к ресурсам, однако при каждом перемещении указателя в мастер гриде будет перевыполняться SQL запрос и загружать сетевой трафик (хотя объём будет невелик).
В нашем приложении я буду использовать второй подход. Для этого необходимо написать обработчик события изменения текущей записи для компонента BindingSource.
Метод для загрузки данных о позициях счёт-фактуры выглядит следующим образом:
В качестве проекции мы использовали класс InvoiceLineView.
Замечу, что в отличие от класса InvoiceView здесь отсутствует метод для загрузки одной текущей записи. Здесь скорость перезагрузки детейл грида не настолько критична, поскольку один документ не содержит тысячи позиций, однако при желании вы можете реализовать такой метод.
Добавим специальное свойство для получения текущей строки документа выделенной в детейл гриде.
В методах для добавления, редактирования и удаления мы покажем, как работать с хранимыми процедурами в Entity Framework. Например, метод для добавления новой записи выглядит так:
Здесь обновление записи мастер грида требуется потому, что одно из его полей (TotalSale) содержит агрегированную информацию по строкам документа.
Метод для обновления записи реализован так.
Метод для удаления записи реализован так.
В методах для добавления и редактирования позиций счёт-фактуры мы использовали форму для редактирования.

Для отображения товара мы будем использовать TextBox. По нажатию кнопки, расположенной рядом, будет вызываться модальная форма с гридом для выбора товара. В качестве модальной окна для выбора продукта используем ту же форму, что была создана для их отображения. Код обработчика нажатия кнопки и инициализации формы будет выглядеть следующим образом:
Работа с транзакциями
Когда мы вызываем при добавлении, обновлении, удалении метод SaveChanges(), то фактически Entity Framework неявно стартует и завершает транзакцию. Поскольку используется отсоединённая модель, то все операции происходят в рамках одной транзакции. Кроме того EF автоматически стартует и завершает транзакцию при каждом извлечении данных. Рассмотрим работу автоматических транзакций на следующем примере. Допустим нам необходимо сделать скидку на товары, выделенные в гриде. Код без явного использования транзакций будет выглядеть следующим образом:
Допустим, мы выбрали 10 товаров. В этом случае будет неявно использовано 10 транзакций для поиска товара по идентификатору и одиннадцатая для сохранения изменений. В данном случае можно использовать всего одну транзакцию, если использовать явное управление транзакциями. Например, вот так:
В данном случае мы стартовали транзакцию с параметрами по умолчанию. Для того чтобы задавать свои параметры транзакции необходимо использовать метод UseTransaction.
Ну вот. Теперь у нас для всего набора обновлений используется всего одна транзакция, и нет лишних команд для поиска данных. Осталось только добавить диалог для ввода значения скидки и обновление данных в гриде. Попробуйте сделать это самостоятельно.
Надеюсь, эта статья помогла вам разобраться в особенностях написания приложения на C# с использованием Entity Framework при работе с СУБД Firebird.