Как подключить entity framework к проекту с
Данное руководство устарело. Актуальное руководство: Руководство по Entity Framework Core
Последнее обновление: 24.10.2018
Чтобы непосредственно начать работать с Entity Framework, создадим первое приложение. Для этого нам нужна будет, во-первых, среда разработки. В качестве среды разработки выберем Visual Studio 2017.
В окне создания проекта в левой части выберем секцию Visual C#->Windows Desktop и в центральной части окна в качестве типа проекта выберем Console App (.NET Framework) .
Теперь первым делом добавим новый класс, который будет описывать данные. Пусть наше приложение будет посвящено работе с пользователями. Поэтому добавим в проект новый класс User:
public class User < public int Id < get; set; >public string Name < get; set; >public int Age < get; set; >>
Это обычный класс, который содержит некоторое количество автосвойств. Каждое свойство будет сопоставляться с отдельным столбцом в таблице из бд.
Надо отметить, что Entity Framework при работе с Code First требует определения ключа элемента для создания первичного ключа в таблице в бд. По умолчанию при генерации бд EF в качестве первичных ключей будет рассматривать свойства с именами Id или [Имя_класса]Id (то есть UserId). Если же мы хотим назвать ключевое свойство иначе, то нам нужно будет внести дополнительную логику на c#.
Теперь для взаимодействия с бд нам нужен контекст данных. Это своего рода посредник между бд и классами, описывающими данные. Но, у нас по умолчанию еще не добавлена библиотека для EF. Чтобы ее добавить, нажмем на проект правой кнопкой мыши и выберем в контекстном меню Manage NuGet Packages.
Затем в появившемся окне управления NuGet-пакетами в окне поиска введем слово «Entity» и выберем пакет собственно Entity Framework и установим его:
После установки пакета добавим в проект новый класс UserContext:
using System; using System.Collections.Generic; using System.Data.Entity; namespace FirstEF6App < class UserContext : DbContext < public UserContext() :base("DbConnection") < >public DbSet Users < get; set; >> >
Основу функциональности Entity Framework составляют классы, находящиеся в пространстве имен System.Data.Entity. Среди всего набора классов этого пространства имен следует выделить следующие:
- DbContext : определяет контекст данных, используемый для взаимодействия с базой данных.
- DbModelBuilder : сопоставляет классы на языке C# с сущностями в базе данных.
- DbSet/DbSet : представляет набор сущностей, хранящихся в базе данных
В любом приложении, работающим с БД через Entity Framework, нам нужен будет контекст (класс производный от DbContext) и набор данных DbSet, через который мы сможем взаимодействовать с таблицами из БД. В данном случае таким контекстом является класс UserContext.
В конструкторе этого класса вызывается конструктор базового класса, в который передается строка «DbConnection» — это имя будущей строки подключения к базе данных. В принципе мы можем не использовать конструктор, тогда в этом случае строка подключения носила бы имя самого класса контекста данных.
И также в классе определено одно свойство Users, которое будет хранить набор объектов User. В классе контекста данных набор объектов представляет класс DbSet . Через это свойство будет осуществляться связь с таблицей объектов User в бд.
И теперь нам надо установить подключение к базе данных. Для установки подключения обычно используется файл конфигурации приложения. В проектах для десктопных приложений файл конфигурации называется App.config (как в нашем случае), в проектах веб-приложений — web.config . В нашем случае, поскольку у нас консольное приложение, это файл App.config . После добавления Entity Framework он выглядит примерно следующим образом:
Содержимое файла в каждом конкретном случае может отличаться. Но в любом случае после добавления EntityFramework в проект в нем будет содержаться элемент configSections. И после закрывающего тега добавим следующий элемент:
Все подключения к источникам данных устанавливаются в секции connectionStrings , а каждое отдельное подключение представляет элемент add . В конструкторе класса контекста UserContext мы передаем в качестве названия подключения строку «DbConnection», поэтому данное название указывается в атрибуте name=»DBConnection» .
Настройку строки подключения задает атрибут connectionString . В данном случае мы устанавливаем название базы данных, с которой будем взаимодействовать — userstore.
Теперь перейдем к файлу Program.cs и изменим его содержание следующим образом:
using System; namespace FirstEF6App < class Program < static void Main(string[] args) < using(UserContext db = new UserContext()) < // создаем два объекта User User user1 = new User < Name = "Tom", Age = 33 >; User user2 = new User < Name = "Sam", Age = 26 >; // добавляем их в бд db.Users.Add(user1); db.Users.Add(user2); db.SaveChanges(); Console.WriteLine("Объекты успешно сохранены"); // получаем объекты из бд и выводим на консоль var users = db.Users; Console.WriteLine("Список объектов:"); foreach(User u in users) < Console.WriteLine(". - ", u.Id, u.Name, u.Age); > > Console.Read(); > > >
Так как класс UserContext через родительский класс DbContext реализует интерфейс IDisposable , то для работы с UserContext с автоматическим закрытием данного объекта мы можем использовать конструкцию using .
В конструкции using создаются два объекта User и добавляются в базу данных. Для их сохранения нам достаточно использовать метод Add : db.Users.Add(user1)
Чтобы получить список данных из бд, достаточно воспользоваться свойством Users контекста данных: db.Users
В результате после запуска программа выведет на консоль:
Объекты успешно сохранены Список объектов: 1.Tom - 33 2.Sam - 26
Таким образом, Entity Framework обеспечивает простое и удобное управление объектами из базы данных. При том в данном случае нам не надо даже создавать базу данных и определять в ней таблицы. Entity Framework все сделает за нас на основе определения класса контекста данных и классов моделей. И если база данных уже имеется, то EF не будет повторно создавать ее.
Наша задача — только определить модель, которая будет храниться в базе данных, и класс контекста. Поэтому данный подход называется Code First — сначала пишется код, а потом по нему создается база данных и ее таблицы.
Возникает вопрос, а где же находится БД? Чтобы физически увидеть базу данных, мы можем подключиться к ней из Visual Studio через окно View->SQL Server Object Explorer . После этого мы можем увидеть в SQL Server Object Explorer созданную базу данных, посмотреть ее строение, таблицы, открыть и даже изменить данные в таблицах:
Физически база данных по умолчанию будет располагаться в папке пользователя, в частности, у меня она размещена в каталоге C:\Users\Eugene\ , только к ее названию буде добавляться стандартное расширение mdf — userstore.mdf.
Настройка подключения к базе данных
При работе с Entity Framework во всех предыдущих примерах мы полагались на соглашения Code-First по автоматическому определению подключения к базе данных. По умолчанию, Code-First создает базу данных на локальном сервере .\SQLEXPRESS, используя полное имя класса контекста для имени базы данных (например, пространство имен + имя класса). Для примера нашего проекта это означает, что Code-First создаст базу данных с именем CodeFirst.SampleContext. Зачастую это поведение необходимо переопределить, в частности мы передавали имя базы данных MyShop в конструкторе класса контекста. В этой статье содержится подробное описание настроек имени базы данных и подключения к ней.
Использование конфигурационного файла приложения
Самым простым способом управления подключением к базе данных является использование конфигурационного файла приложения. В файле конфигурации можно переопределить базовые соглашения Code-First и точно указать строку подключения к базе данных. Этот подход особенно полезен, если вы хотите изменить строку подключения в вашем контексте, чтобы указать подключение к удаленной (не локальной) базе данных при развертывании приложения.
В приложениях ASP.NET конфигурационным файлом является файл Web.config, в приложениях другого типа – App.config. При использовании нескольких проектов в одном решении можно допустить ошибку с правильным выбором конфигурационного файла. Например, в нашем приложении сущностная модель находится в проекте библиотеки классов CodeFirst, а непосредственно с данными мы работаем в проекте веб-приложения ASP.NET. Возможно вам покажется правильным, разместить настройки подключения в файле App.config проекта CodeFirst. Однако это является неправильным решением. Entity Framework настраивает базу данных при создании объекта контекста, а не при его объявлении. В примерах, приводившихся ранее, мы использовали объект контекста в коде веб-форм, поэтому настройки строки подключения нужно указывать в файле Web.config веб-приложения ASP.NET.
Благодаря такому подходу обеспечивается возможность многоразового использования модели данных. В каждом проекте, где мы ссылаемся на проект CodeFirst, мы можем указать свою строку подключения, т.е. одна модель будет работать с разными базами данных.
Для указания строки подключения используется раздел конфигурации connectionString. По умолчанию, строка подключения должна иметь то же имя, что и файл контекста, при этом можно указать как полное имя так и краткое (т.е SampleContext или CodeFirst.SampleContext). Благодаря этому, Entity Framework автоматически найдет нужную строку подключения в файле конфигурации и использует ее. В примере ниже показано определение строки подключения:
Запустите этот пример и убедитесь, что Code-First создаст новую базу данных с именем MyShop2 для текущей модели. Если вы прорабатывали примеры из предыдущих статей, то пока удалите вызов конструктора базового класса из класса контекста. В результате будет создана следующая база данных:
Настройка подключения в конструкторе класса контекста
Выше вы видели, как задать строку подключения из файла конфигурации так, что контекст будет использовать ее автоматически благодаря соглашениям Code-First. Теперь давайте посмотрим на некоторые способы управления подключением к базе данных из кода.
Класс DbContext помимо конструктора по умолчанию включает в себя несколько перегруженных версий конструкторов. Если вы используете один из этих конструкторов, Code-First не будет использовать соглашения для автоматического поиска строки подключения. Самая простая версия конструктора класса DbContext принимает один строковый параметр. Давайте посмотрим как использовать этот конструктор из производного класса:
public class SampleContext : DbContext < public SampleContext() : base("MyShop") < >public DbSet Customers < get; set; >>
В этом конструкторе передается либо имя базы данных, либо полностью определенная строка подключения. Entity Framework достаточно интеллектуален, чтобы различить просто имя и строку подключения, в данном примере мы указываем имя базы данных.
Обратите внимание, что в этом примере мы вызываем перегруженный конструктор класса DbContext из конструктора по умолчанию производного класса SampleContext. При таком подходе к проектированию, когда вы создаете объект контекста в вашем приложении, строка подключения будет автоматически выбираться из конструктора по умолчанию класса SampleContext. Иногда бывает необходимо указать строку подключения при создании объекта контекста. Для этого можно добавить перегруженный конструктор в класс контекста с вызовом перегруженного конструктора DbContext:
public class SampleContext : DbContext < public SampleContext() < >public SampleContext(string dbNameOrConnection) : base(dbNameOrConnection) < >// . >
Теперь в коде работы с данными, при создании объекта класса контекста вы можете указывать имя базы данных или строку подключения:
protected void Page_Load(object sender, EventArgs e)
В этом примере извлекаются данные всех покупателей из таблицы Customers базы данных MyShop2, т.к. мы указали полную строку подключения к этой базе данных. Если в данном примере вы создадите объект контекста с использованием конструктора по умолчанию:
SampleContext context = new SampleContext();
то Code-First использует соглашения по автоматическому поиску строки подключения, и, если не найдет строку подключения с именем SampleContext или CodeFirst.SampleContext, то попытается подключиться к базе данных с именем CodeFirst.SampleContext.
У вас также может возникнуть вопрос, как явно передать конструктору класса контекста имя строки подключения, если оно не соответствует имени класса контекста. Для этого можно использовать укороченную строку подключения с единственным параметром name:
public class SampleContext : DbContext < public SampleContext() : base("name=MyConnectionStringName") < >// . >
Теперь Code-First будет искать в конфигурационном файле строку подключения с именем MyConnectionStringName.
Повторное использование подключения к базе данных
Одна из перегруженных версий конструктора DbContext принимает объект подключения DbConnection из пространства имен System.Data.Common. Использование этого объекта может быть полезно, если вы хотите указать в нескольких объектах контекста один и тот же объект подключения и не хотите каждый раз указывать имя базы данных или строки подключения. Т.е. объект DbConnection может храниться в определенном месте приложения и вы можете ссылаться на него всякий раз, когда создаете объект контекста. Ниже показан пример:
using System.Data.Entity; using System.Data.Entity.ModelConfiguration; using System.Data.Common; namespace CodeFirst < // Определяет строку подключения к бд MyShop public class DbConnectionToMyShop : DbConnection < public DbConnectionToMyShop() < this.ConnectionString = ". "; >> public class SampleContext : DbContext < public SampleContext() : base(new DbConnectionToMyShop(), contextOwnsConnection: false) < >public SampleContext(DbConnection connection) : base(connection, false) < >// . > >
В этом примере мы создали класс DbConnectionToMyShop, для подключения к базе данных MyShop. Объект этого класса передается в конструкторе по умолчанию класса контекста. Мы также создали для удобства перегруженный конструктор — в коде приложения вы можете просто передать нужный объект подключения. Классы подключений можно определить в одном файле и затем использовать повсеместно в приложении. Второй параметр в этом конструкторе contextOwnsConnection указывает, нужно ли очищать объект подключения при удалении объекта контекста.
Настройка соглашений подключения в Code-First
Последним способом управления подключением к базе данных, является замена соглашений, которые использует Code-First. Соглашения по конфигурации подключения определяются с помощью интерфейса IDbConnectionFactory. Вы можете реализовать этот интерфейс и передать его методу SetDefaultConnectionFactory() класса DbConfiguration, переопределив тем самым соглашения по умолчанию Code-First.
Соглашения по умолчанию реализует класс SqlConnectionFactory из пространства имен System.Data.Entity.Infrastructure. Поведение по умолчанию определяет, что поставщиком базы данных будет поставщик SQL Server (сборка System.Data.SqlClient), имя сервера — .\SQLEXPRESS, а для доступа к серверу используется Windows-аутентификация (сервер доступен для текущего пользователя системы). Вы можете переопределить данные соглашения, например, для того, чтобы явно указать Entity Framework что вы хотите работать с поставщиком MySQL.
В примере ниже показано, как переопределить эти соглашения, используя класс конфигурации, унаследованный от DbConfiguration:
using System.Data.Entity; using System.Data.Entity.ModelConfiguration; using System.Data.Entity.Infrastructure; namespace CodeFirst < // Класс конфигурации public class MyDbConfig : DbConfiguration < public MyDbConfig() < SqlConnectionFactory defaultFactory = new SqlConnectionFactory("Server=MyDbServer;User=username;Password=12345;"); this.SetDefaultConnectionFactory(defaultFactory); >> [DbConfigurationType(typeof(MyDbConfig))] public class SampleContext : DbContext < public SampleContext() : base("MyShop") < >// . > >
В этом примере мы изменяем имя сервера, а также указываем, что для доступа к серверу должна использоваться SQL-аутентификация, на основе имени пользователя и пароля. Обратите внимание, чтобы указать классу контекста, чтобы он использовал эту конфигурацию, используется атрибут DbConfigurationType. Чтобы зарегистрировать новый класс конфигурации, в файле Web.config веб-приложения нужно удалить раздел defaultConnectionFactory:
Также вы можете установить конфигурацию для всех классов контекста в приложении и не использовать атрибут DbConfigurationType. Для этого укажите свойство codeConfigurationType раздела конфигурации entityFramework:
Здесь указывается ссылка на класс конфигурации и имя сборки, где этот класс располагается. Для настройки поставщика базы данных вы можете использовать метод SetProviderServices() класса конфигурации или использовать элементы provider разделе entityFramework файла конфигурации:
public class MyDbConfig : DbConfiguration < public MyDbConfig() < // . this.SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance); >>
В примерах выше показано использование стандартного поставщика данных SQL Server, но вы можете указать другие поставщики баз данных, которые требуются в вашем приложении (MySQL, Oracle и т.п.)
Работа с базой данных
Entity Framework представляет ORM-решение, которое позволяет автоматически связать классы языка C# с таблицами в базе данных. Entity Framework Core поддерживает большинство популярных СУБД, таких как MS SQL Server, SQLite, MySQL, Postres. В данном случае мы будем работать через Entity Framework Core с базами данных в MS SQL Server.
Детально ознакомиться с работой с Entity Framework Core можно в соответствуюшем руководстве, здесь же мы сосредоточимся прежде всего на тех моментах, которые характерны для веб-приложения ASP.NET Core.
Для работы с базами данных MS SQL Server через Entity Framework Core необходим пакет Microsoft.EntityFrameworkCore.SqlServer . По умолчанию он отсутствует в проекте, поэтому его надо добавить, например, через пакетный менеджер Nuget:
Далее добавим в проект класс, которые будет представлять данные. Пусть он будет называться User и будет иметь следующий код:
public class User < public int Id < get; set; >public string Name < get; set; >= ""; // имя пользователя public int Age < get; set; >// возраст пользователя >
Этот класс представляет те объекты, которые будут храниться в базе данных.
Для взаимодействия с базой данных через Entity Framework Core необходим контекст данных — класс, унаследованный от класса Microsoft.EntityFrameworkCore.DbContext . Поэтому добавим в проект новый класс, который назовем ApplicationContext (название класса контекста произвольное):
using Microsoft.EntityFrameworkCore; public class ApplicationContext : DbContext < public DbSetUsers < get; set; >= null!; public ApplicationContext(DbContextOptions options) : base(options) < Database.EnsureCreated(); // создаем базу данных при первом обращении >protected override void OnModelCreating(ModelBuilder modelBuilder) < modelBuilder.Entity().HasData( new User < Name = "Tom", Age = 37 >, new User < Name = "Bob", Age = 41 >, new User < Name = "Sam", Age = 24 >); > >
Свойство DbSet представляет собой коллекцию объектов, которая сопоставляется с определенной таблицей в базе данных. То есть свойство Users будет представлять таблицу, в которой будут храниться объекты User.
Класс DbSet, как и другие типы, является ссылочным. А, начиная с C# 10 и .NET 6 автоматически применяется функциональность ссылочных nullable-типов. И переменные/свойства тех типов, которые не являются nullable, следует инициализировать некотором значением перед их использованием. Чтобы выйти из этой ситуации мы можем инициализировать свойство с помощью выражения null! , которое говорит, что данное свойство в принципе не будет иметь значение null. Потому что в реальности конструктор базового класса DbContext гарантирует, что все свойства типа DbSet будут инициализированы и соответственно в принципе не будут иметь значение null.
В конструкторе класса ApplicationContext через параметр options будут передаваться настройки контекста данных. А в самом конструкторе с помощью вызова Database.EnsureCreated() по определению модели будет создаваться база данных (если она отсутствует).
Кроме того, в методе OnModelCreating() настраивается некоторая начальная конфигурация модели. В частности, с помощью метода modelBuilder.Entity().HasData() в базу данных добавляются три начальных объекта
Конфигурация и строка подключения
Чтобы подключаться к базе данных, нам надо задать параметры подключения. Это можно сделать либо в коде C#, либо в файле конфигурации. Выберем второй способ. Для этого изменим файл appsettings.json . По умолчанию он содержит только настройки логгирования:
< "Logging": < "LogLevel": < "Default": "Information", "Microsoft.AspNetCore": "Warning" >>, "AllowedHosts": "*" >
Теперь изменим его, добавив определение строки подключения:
< "ConnectionStrings": < "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=applicationdb;Trusted_Connection=True;" >, "Logging": < "LogLevel": < "Default": "Information", "Microsoft.AspNetCore": "Warning" >>, "AllowedHosts": "*" >
В данном случае мы будем использовать упрощенный движок базы данных LocalDB, который представляет легковесную версию SQL Server Express, предназначенную специально для разработки приложений. Об этом говорит параметр Server=(localdb)\\mssqllocaldb . Ну а сама база данных будет называться applicationdb .
Добавление контекста данных EF Core в качестве сервиса
Контекст данных, через который идет взаимодействие с базой данных, передается в приложение в качестве сервиса через механизм внедрения зависимостей. Поэтому для работы с Entity Framework Core необходимо добавить класс контекста данных в коллекцию сервисов приложения:
using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(); // получаем строку подключения из файла конфигурации string connection = builder.Configuration.GetConnectionString("DefaultConnection"); // добавляем контекст ApplicationContext в качестве сервиса в приложение builder.Services.AddDbContext(options => options.UseSqlServer(connection)); var app = builder.Build(); app.Run();
Для использования контекста данных ему надо передать строку подключения, которая выше была определена в файл конфигурации appsettings.json. Поэтому сначала считываем строку подключения под названием «DefaultConnection»:
string connection = builder.Configuration.GetConnectionString("DefaultConnection");
Для получения строки конфигурации для объекта IConfiguration, который представляет конфигурацию, определен метод расширения GetConnectionString() , в который передается название строки подключения.
Для добавления контекста данных в качестве сервиса у объекта коллекции сервисов IServiceCollection определен метод AddDbContext() , который типизируется классом контекста данных:
builder.Services.AddDbContext(options => options.UseSqlServer(connection));
Этот метод в качестве параметра принимает делегат, который настраивает подключение. В частности, с помощью вызова options.UseSqlServer() настраивается подключение к серверу MS SQL Server, а в качестве параметра в этот вызов передается строка подключения.
Обращение к базе данных
Подключив контекст данных мы можем с его помощью обращаеться к базе данных. Например, в качестве теста получим добавляемые по умолчанию данные:
using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(); string connection = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContext(options => options.UseSqlServer(connection)); var app = builder.Build(); // получение данных app.MapGet("/", (ApplicationContext db) => db.Users.ToList()); app.Run();
Поскольку контекст данных добавлен в сервисы, то мы можем его получить в обработчике конечной точки:
app.MapGet("/", (ApplicationContext db) => db.Users.ToList());
В данном случае клиенту отправляется список добавленных в БД по умолчанию объектов User в формате JSON:
Основы Entity Framework Core. Часть [0]
В этой части будет кратко рассказано о технологии Entity Framework Core, а также её установки в свой проект.
Кратко о технологии
Общая цель EF — предоставить возможность взаимодействия с данными из реляционных баз данных с использованием объектной модели, которая отображается напрямую на бизнес-объекты в создаваемых приложениях. Например, вместо того, чтобы трактовать пакет данных как коллекцию строк и столбцов, вы можете оперировать с коллекцией строго типизированных объектов, называемых сущностями. Такие сущности хранятся в специализированных классах коллекций, поддерживающих LINQ, что позволяет выполнять операции доступа к данным в коде С#.
Entity Framework Core (также известная как EF Core) представляет собой пакет объектно-реляционного отображения (object-relational mapping — ОRМ) производства Microsoft, который позволяет приложениям .NET Core хранить данные в реляционных базах данных. Entity Framework Core решает одну основную задачу: сохранение объектов .NET в базе данных (БД) и извлечение их в более позднее время.
Более подробно можете почитать на здесь и здесь.
Создание проекта
Для начала создадим консольное приложение в Visual Studio 2022. Как вариант, это можно сделать сразу через консоль:
dotnet new sln -n EntityFrameworkBase #создаем проект dotnet new console -lang c# -n ChapterZero -o .\ChapterZero -f net6.0 #создаем решение dotnet sln .\EntityFrameworkBase.sln add .\ChapterZero #прикрепляем к проекту решение
Или запускайте Visual Studio и выполняйте пошагово действия, которые показаны ниже:
- Создаем новый проект.
- Создаем консольное приложение.
- Придумываем название проекта, выбираем путь, по которому будет располагаться проект, и, наконец, придумываем название решения.
После выполненных действий в обозревателе решений (Solution Explorer) должно быть отображено следующее:
Установка EF Core в свой проект
Установить все нужные библиотеки можно как и выше через консоль:
dotnet add ChapterZero package Microsoft.EntityFrameworkCore.Design dotnet add ChapterZero package Microsoft.EntityFrameworkCore.SqlServer dotnet add ChapterZero package Microsoft.EntityFrameworkCore
Или в Visual Studio через NuGet Package Manager. Процесс показан ниже:
- Переходим в Tools / NuGet Package Manager / Manage NuGet Packages for Solution.
- Переходим в Browse и ищем Microsoft.EntityFrameworkCore.
- Устанавливаем в проект.
Для Microsoft.EntityFrameworkCore.SqlServer и Microsoft.EntityFrameworkCore.Design повторить тоже самое. После установки всех нужных компонентов при переходе во вкладку Installed должно отобразиться следующее:
На этом пока что закончим. Код проекта тут.
Спасибо вам за прочтение.