Entity framework добавление данных в базу данных
Данное руководство устарело. Актуальное руководство: Руководство по Entity Framework Core
Создадим полноценное приложение, которое будет выполнять все эти операции. Итак, создадим новый проект по типу Windows Forms. Новое приложение будет работать с базой данных футболистов. В качестве подхода взаимодействия с БД выберем Code First.
Вначале добавим в проект новый класс, который описывает модель футболистов:
Тут всего четыре свойства: id, имя, позиция на поле и возраст. Также добавим в проект через NuGet пакет Entity Framework и новый класс контекста данных:
В файл конфигурации app.config после секции configSections добавим узел connectionStrings , в котором определим строку подключения DefaultConnection:
Теперь визуальная часть. По умолчанию в проекте уже есть форма Form1. Добавим на нее элемент DataGridView, который будет отображать все данные из БД, а также три кнопки на каждое действие - добавление, редактирование, удаление, чтобы в итоге форма выглядела так:
У элемента DataGridView установим в окне свойств для свойства AllowUserToAddRows значение False , а для свойства SelectionMode значение FullRowSelect , чтобы можно было выделять всю строку.
Это основная форма, но добавление и редактирование объектов у нас будет происходить на вспомогательной форме. Итак, добавим в проект новую форму, которую назовем PlayerForm. Она будет иметь следующий вид:
Здесь у нас текстовое поле для ввода имени, далее выпадающий список ComboBox, в который мы через свойство Items добавляем четыре позиции. И последнее поле - NumericUpDown для ввода чисел для указания возраста. У всех этих трех полей установим свойство Modifiers равным Protected Internal , чтобы эти поля были доступны из главной формы.
Также есть две кнопки. Для кнопки "ОК" в окне свойств для свойства DialogResult укажем значение OK, а для кнопки "Отмена" для того же свойства установим значение Cancel.
Никакого кода данная форма не будет содержать. Теперь перейдем к основной форме Form1, которая и будет содержать всю логику. Весь ее код:
Чтобы получить данные из бд, используется выражение db.Players. Однако нам надо кроме того выполнить привязку к элементу DataGridView и динамически отображать все изменения в случае добавления, редактирования или удаления. Поэтому вначале используется метод db.Players.Load() , который загружает данные в объект DbContext, а затем выполняется привязка ( dataGridView1.DataSource = db.Players.Local.ToBindingList() )
Создание частично заполненных сущностных типов
В предыдущем коде явно создается новый сущностный тип, но при этом используется другой подход. Сущностные типы Entity Framework включают статический метод по имени Create[T], где [T] — имя типа. Например, сущностный тип Customer будет включать метод под названием CreateCustomer, а тип Order — метод по имени CreateOrder. Эти методы имеют параметры для каждого поля сущностного типа, которое не допускает значения null. На рисунке ниже показана таблица Customers базы Northwind в среде SQL Server Management Studio. Здесь видно, что все столбцы могут содержать значения null, за исключением CustomerID и CompanyName:
Таким образом, статический метод Customer.CreateCustomer имеет следующую сигнатуру, которая требует параметров для поля с обязательным заполнением:
Преимущество использования метода Create[T] состоит в том, что он позволяет избежать исключений при попытке сохранить сущностный тип со значением null в не допускающем null поле. Ниже приведен код создания и добавления записи посредством этого приема:
Как видите, здесь был создан новый экземпляр Customer с использованием метода CreateCustomer, которому переданы значения двух полей, не допускающие null. Затем с помощью общедоступных свойств типа Customer устанавливаются другие необходимые значения.
Редактирование
Редактирование имеет похожую логику. Только вначале мы передаем значения свойств объекта во вторую форму, а после получаем с нее же измененные значения для свойств объекта.
В данном случае контекст данных автоматически отслеживает, что объект был изменен, и при вызове метода db.SaveChanges() будет сформировано SQL-выражение UPDATE для данного объекта, которое обновит объект в базе данных.
Вставка связанных объектов
Связи между таблицами в Entity Framework описываются с помощью навигационных свойств. В нашей модели существует связь один-ко-многим между классами Customer и Order, которая выражается с помощью пары навигационных свойств Customer.Orders и Order.Customer. Если навигационное свойство имеет тип ссылки, то для вставки связанных данных нужно просто инициализировать это свойство. Если навигационное свойство имеет тип коллекции, то нужно использовать ее метод Add() для добавления новой записи. Следует помнить, что изменения могут быть сделаны с одного или с двух концов связи (если используется пара навигационных свойств).
Давайте предположим, что нам нужно вставить новый заказ для добавленного в предыдущем примере пользователя “Иван Иванов”:
В этом примере мы извлекаем пользователя с фамилией “Иванов” и добавляем для него новый заказ. Как видите, мы извлекаем все данные пользователя в первом запросе. Если таблица Customers содержит много столбцов с большим объемом данных, то такой подход плохо влияет на производительность. В таком случае можно извлечь только первичный ключ для покупателя (свойство CustomerId), а экземпляру класса Order добавить не ссылку в навигационном поле, а инициализировать внешний ключ. В примере нашей модели мы не определяли явно внешний ключ в классе Order, поэтому Code-First генерировал внешний ключ автоматически. Чтобы использовать описанный выше прием, мы должны будем добавить явно внешний ключ в класс Order:
Перед тем, как перейти к следующему примеру вы должны воссоздать базу данных с этой новой моделью, используя инициализаторы базы данных или удаляя ее вручную, как это описывалось при обсуждении Code-First. Теперь можно будет использовать этот внешний ключ в экземпляре класса Order:
В предыдущих примерах мы добавляли новый связанный объект для уже существующего базового объекта. В примере ниже показано, как при создании базового объекта, можно добавить сразу связанные объекты в одном запросе. Здесь мы создаем нового покупателя Петр Петров с двумя новыми заказами:
Для этого примера Entity Framework создаст три SQL-запроса INSERT – один для вставки нового покупателя, а два для вставки связанных с ним заказов.
Удаление
С удалением проще всего: получаем по id нужный объект в бд и передаем его в метод db.Players.Remove(player) . Данный метод установит статус объекта в Deleted , благодаря чему Entity Framework при выполнении метода db.SaveChanges() сгенерирует SQL-выражение DELETE.
В этой статье мы рассмотрим, как можно вставлять новые записи в таблицу базы данных, а в последующих статьях рассмотрим вопросы обновления и удаления данных. Стоит отметить, что для сохранения любых изменений используется метод SaveChanges() класса контекста DbContext.
Метод SaveChanges() будет вызывать обновление в источнике данных, который отвечает за перевод изменений в сущностных объектах в правильные инструкции SQL, которые выполняются с базой данных. Т.к. Entity Framework известно о связях между таблицами, определяемых с помощью навигационных свойств, этот фреймворк обеспечит создание нужных SQL-инструкций, чтобы эти изменения применялись в правильном порядке. В контексте нашего примера, вы можете, например, удалить покупателя. Entity Framework автоматически распознает связь между классами модели Customer и Order и удалит все связанные с покупателем заказы. Это говорит о том, что Entity Framework позволяет вносить изменения, которые автоматически влияют на отдельные объекты, на пару связанных объектов или на весь граф объектов.
Удаление
Удаление производится с помощью метода Remove :
Данный метод установит статус объекта в Deleted, благодаря чему Entity Framework при выполнении метода db.SaveChanges() сгенерирует SQL-выражение DELETE.
Если необходимо удалить сразу несколько объектов, то можно использовать метод RemoveRange() :
Создание универсального метода вставки
В предыдущей статье, где мы рассматривали создание универсального метода для загрузки данных, мы создали новый класс Repository и обобщенный метод Select(). Давайте создадим подобный метод Insert() для универсальной вставки данных в базу:
В этом примере мы создаем два метода, первый из которых служит для вставки одного объекта, а второй вставит коллекцию объектов. Для вставки объекта entity используется средство состояний Entity Framework – альтернативное средство вставки объектов, благодаря которому мы указываем состояние сущностного объекта из перечисления EntityState. В нашем случае мы используем состояние EntityState.Added.
Обратите внимание, что в методе Inserts() мы отключили некоторые настройки конфигурации класса контекста. В частности свойство AutoDetectChangesEnabled отключает создание уведомлений при изменении сущностных данных, а ValidateOnSaveEnabled отключает проверку достоверности запроса при сохранении. Предполагается, что в этом методе могут вставляться тысячи записей, поэтому нужно оптимизировать эти настройки.
Теперь вы можете использовать эти методы для создания простых запросов, не беспокоясь о деталях реализации вставки данных:
Для выполнения вставки необходимо предпринять четыре шага. Первый из них — создание ObjectContext. Это первый шаг для всех операций LINQ to Entities, и он встречается во всех примерах. Получив объектный контекст, можно создать новый экземпляр сущностного типа, например, Customer, и наполнить данными его поля. Заполненный сущностный тип затем добавляется к ObjectSet. Последний шаг — сохранение новых данных посредством метода SaveChanges:
Как видите, в предыдущем коде шаги пронумерованы. На первом шаге строится ObjectContext за счет создания нового экземпляра производного класса NorthwindEntities. На втором шаге создается новый экземпляр сущностного типа Customer и применяется инициализация объекта для заполнения полей. На третьем шаге в коллекцию Customers добавляется новый экземпляр Customer вызовом метода AddObject свойства Customers объекта ObjectContext. Это свойство в базе данных имеет тип ObjectSet. На последнем шаге вызывается метод SaveChanges для сохранения новой записи в базе данных.
В оставшейся части кода данные запрашиваются, чтобы убедиться, что новая запись была создана.
Редактирование
При изменении объекта Entity Framework сам отслеживает все изменения, и когда вызывается метод SaveChanges() , будет сформировано SQL-выражение UPDATE для данного объекта, которое обновит объект в базе данных.
Но надо отметить, что в данном случае действие контекста данных ограничивается пределами конструкции using, которая определяет область действия объекта ApplicationContext. Но рассмотрим другой пример. Мы получаем объект в одном месте,а обновляем в другом. Например:
Несмотря на то, что объект user не равен null, имеется в базе данных, но во втором блоке using обновления соответствующего объекта в БД не произойдет. Потому что объект User больше не отслеживается контекстом данных. И в этом случае во второй конструкции using, где происходит редактирование, нам надо использовать метод Update:
При необходимости обновить одновременно несколько объектов, применяется метод UpdateRange() :
Добавление
При добавлении объекта использует вторая форма:
Для добавления объекта используется метод Add , определенный у класса DbSet. В этот метод передается новый объект, свойства которого формируются из полей второй формы. Метод Add устанавливает значение Added в качестве состояния нового объекта. Поэтому метод db.SaveChanges() сгенерирует выражение INSERT для вставки модели в таблицу.
Вставка одного объекта
Добавление нового объекта с помощью Entity Framework является простой операцией нужно только создать новый экземпляр вашего объекта и добавить его в коллекцию сущностных объектов DbSet с помощью метода Add(). Ниже показан пример, как мы можем вставить нового пользователя в базу данных (мы используем все тот же проект консольного приложения с которым работали в предыдущих статьях):
При сохранении изменений в базе данных с помощью метода SaveChanges(), Entity Framework сгенерирует следующий SQL-запрос:
Обратите внимание на отображение нашего управляемого кода на этот SQL-запрос. Для вставки значений используются переменные @0, @1 и @2. Они инициализируются при компиляции приложения. Также, после инструкции INSERT следует инструкция SELECT, которая выбирает значение первичного ключа (в нашем случае CustomerId) для вновь вставленной записи. Благодаря этому, Entity Framework передает значение этого ключа переменной customer в коде. Т.е. после вставки данных, мы можем изменить или удалить этот объект, не извлекая его снова из базы. Чтобы убедиться, что EF инициализирует свойство первичного ключа в объекте модели при вставке в базу данных, можно изменить немного предыдущий пример:
Ниже показан вывод в консоли после запуска этого примера:
Добавление
При добавлении объекта использует вторая форма:
Для добавления объекта используется метод Add , определенный у класса DbSet. В этот метод передается новый объект, свойства которого формируются из полей второй формы. Метод Add устанавливает значение Added в качестве состояния нового объекта. Поэтому метод db.SaveChanges() сгенерирует выражение INSERT для вставки модели в таблицу.
Реализация шаблона “найти или вставить”
В вашем приложении возможно понадобится реализовать простой шаблон “найти или вставить” (find or add), в котором вы проверяете, существует ли объект данных в базе, если нет, то создаете новый объект. Т.к. метод DbSet.Add() возвращает экземпляр сущностного класса модели, реализовать этот шаблон с помощью Entity Framework довольно просто:
Добавление
Для добавления объекта используется метод Add , определенный у класса DbSet, в который передается добавляемый объект:
Метод Add устанавливает значение Added в качестве состояния нового объекта. Поэтому метод db.SaveChanges() сгенерирует выражение INSERT для вставки модели в таблицу.
Если нам надо добавить сразу несколько объектов, то мы можем воспользоваться методом AddRange() :
Вставка присоединенных сущностных объектов
Класс ObjectContext обнаруживает присоединения между сущностными объектами и гарантирует их автоматическое сохранение в базе данных с помощью метода SaveChanges. Помните, что сущностные объекты присоединяются тогда, когда между ними существует отношение внешнего ключа. В следующем пример показано, как это работает:
В этом примере создается новый объект Customer, а свойство-коллекция Orders инициализируется единственным новым заказом. При вызове метода SaveChanges объект ObjectContext сохраняет и Customers, и Orders. Явно добавлять Order в коллекцию Orders типа ObjectSet не понадобится.
Создавать присоединенные объекты вместе подобным образом не обязательно. Их можно создавать отдельно и затем ассоциировать друг с другом. Ниже показана видоизмененная часть предыдущего примера:
В коде объекты Customer и Order создавались отдельно и затем были присоединены друг к другу вызовом метода Orders.Add, который поместил Order в коллекцию ObjectSet, поддерживаемую Customer. При вызове метода SaveChanges объект ObjectContext обнаруживает новый Order и сохраняет его в базе данных.
Знайте, что лучший способ присоединять объекты в отношении "один ко многим" предусматривает добавление их к соответствующему ObjectSet на стороне родительского объекта в отношении.
Большинство операций с данными так или иначе представляют собой CRUD операции (Create, Read, Update, Delete), то есть создание, получение, обновление и удаление. Entity Framework Core позволяет легко выполнять все эти действия.
Затем добавим в проект класс User, объекты которого будут храниться в базе данных:
И добавим класс контекста данных ApplicationContext:
Далее в файле Program.cs определим все базовые операции с данными:
И после выполнения мы получим следующий консольный вывод:
Асинхронный API
Вместо метода SaveChanges() для асинхронного выполнения зароса к бд можно использовать его асинхронный двойник - SaveChangesAsync() . Также, для добавления данных определены асинхронные методы AddAsync и AddRangeAsync . Пример применения асинхронного API:
Всем доброго времени суток. На связи Алексей Гулынин. В данной статье я бы хотел рассказать про первый подход, который используется в Entity Framework — Database First.Из названия понятно, что вначале у нас есть база данных. На основе базы данных у нас создаётся объектная модель (классы).
Давайте с нуля в Visual Studio создадим простую базу данных. База будет состоять из стран и их столиц. Далее на основе данной базы, используя подход Database First , создадим объектную модель и выведем на экран данные из базы.
Выбираем слева "Обозреватель серверов" — "Подключения данных" — "Добавить подключение". Если у вас данной вкладки нет, то в обозреватель серверов можно зайти через пункт меню "Вид" (либо сочетания клавиш "Ctrl + Alt + S"):
Мы будем работать с локальной базой данных localdb, которая встроена в Visual Studio:
Вводим имя "Countries". Так как у нас такой базы нет, то Visual Studio спросит о попытке её создать:
Теперь в обозревателе серверов мы видим, что подключились к базе данных:
Пока что у нас нет ни одной таблицы. Давайте создадим таблицу. Делать всё будем через редактор Visual Studio. Щёлкаем правой кнопкой мыши по "Таблицы" — "Добавить таблицу". Заполняем таблицу, как на скриншоте ниже. В конце нажимаем кнопку "Обновить", чтобы изменения в базе данных сохранились:
Давайте теперь внесём данные в нашу таблицу:
Занесите в таблицу следующие данные:
База данных у нас готова, таблица есть, данные в ней тоже есть. Настало время познакомиться с технологией Entity Framework Database First .
Добавляем в наш проект новый элемент:
Далее выбираем "Конструктор EF из базы данных":
Далее выбираем подключение, которое будет использоваться:
Далее добавляем объекты, которые необходимо включить в нашу модель:
При нажатии на кнопку "Готово" происходит магия Entity Framework, в результате которой будет создана модель и классы:
Обратим внимание на класс "CountriesEntities", который находится в файле "MyModel.Context.cs":
Это некое объектно-ориентированное представление базы данных или, по-другому, контекст . Tables — это и есть наша таблица в базе данных. Если бы у нас было несколько таблиц, то все они были бы здесь. Тип у них был бы DbSet<> .
name=CountriesEntities — это имя нашего подключения.
Контекст хранит все сущности из базы данных.
Теперь переходим к самому интересному (то, ради чего мы всё это проделали). Давайте выведем на экран информацию из базы данных:
Вот таким нехитрым способом, не написав ни одной строчки кода для взаимосвязи с базой данных, мы смогли получить все данные из неё.
В данной статье вы научились создавать локальную базу данных в Visual Studio, а также познакомились с подходом Database First.
На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.
Читайте также: