ASP.NET Core EF Core
Entity Framework Core
ASP.NET Core는 데이타 처리를 위한 Entity Framework Core (전신: Entity Framework 7) 를 내장하고 있다.
EF Core는 이전의 EF 버전들에 비해 가볍고, Cross Platform을 지원한다는 장점이 있으며, Code First Approach만을 지원한다.
EF Core 패키지 추가
ASP.NET Core에서 Entity Framework를 사용하기 위해서는 먼저 EF Core 패키지를 project.json 에 추가하고 해당 패키지를 Nuget으로 다운받아야 한다.
project.json 파일에 아래와 같이 패키지를 등록하고 파일을 저장하면 VS에서 자동으로 패키지를 다운받는다 (Restore Package라고 함).
여기서 Microsoft.EntityFrameworkCore 는 EF 핵심 패키지이고, Microsoft.EntityFrameworkCore.SqlServer는 SQL SqlServer를 사용할 경우 추가하는
Optional 패키지이다.
만약 다른 DB를 사용할 경우 해당 DB의 Provider 패키지를 등록해 주어야 한다.
{
"dependencies": {
"Microsoft.EntityFrameworkCore": "3.1.3",
"Microsoft.EntityFrameworkCore.SqlServer": "3.1.3"
},
}
위와 같은 방식이외에 EF Core 클래스를 사용할 때, Ctrl + . 을 눌러 아래 그림과 같이 Add Package 메뉴를 선택해서 패키지를 project.json에 그때 그때 등록해 줄 수도 있다.
EF Core 모델
EF Core는 Code First 방식만을 지원하는데, 서버에 데이타베이스가 이미 있는 경우 테이블 스키마에 상응하는 C# 클래스를 작성해서 사용하고,
DB가 없는 경우 EF의 Migration 도구를 사용하여 C# 클래스에 상응하는 데이타베이스와 테이블을 생성할 수 있다.
아래 예제는 간단한 EF 모델 클래스와 DbContext 클래스를 정의한 것이다.
using Microsoft.EntityFrameworkCore;
namespace CoreApp1.Models
{
public class MyDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string cn = "Server=.;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true";
optionsBuilder.UseSqlServer(cn);
}
public DbSet<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
}
}
만약 기존에 DB가 이미 있는 경우, 위 코드는 별도의 작업 없이 동작하지만, DB가 없어 EF로부터 새로 생성할 경우는 아래에 설명하는 EF Migration 작업을 진행하여야 한다.
EF Core Migration 작업
EF Core에서 Code First C# 모델 클래스로부터 데이타베이스와 테이블을 생성하기 위해서는 Migration 이라는 작업을 진행한다.
Migration은 초기 DB/테이블 생성 뿐만 아니라, 중간에 테이블 구조가 변경될 경우 이러한 변화를 DB에 적용하는 작업을 한다.
이전 EF 버전들은 Windows의 Powershell을 사용하여 Package Manager Console에서 Migration 명령을 실행할 수 있었는데,
EF Core는 Cross Platform을 지원하기 때문에 타 OS에서 사용할 수 있도록 dotnet 명령을 사용한 Command Line 명령을 사용하게 되었다.
다만, EF Core는 Package Manager Console에서 기존 Powershlell 방식을 계속 지원하고 있는데, 이는 내부적으로 dotnet 명령을 백그라운드에서 실행하는 것이다.
EF Core에서 EF Migration 명령을 실행하기 위해서는 아래와 같은 EF Core 패키지들을 설치한다.
Microsoft.EntityFrameworkCore: 3.1.3
Microsoft.EntityFrameworkCore.SqlServer: 3.1.3
Microsoft.EntityFrameworkCore.Tools: 3.1.3
Microsoft.EntityFrameworkCore.Design: 3.1.3
[참고] ASP.NET Core 3에서 예전과 달리 dotnet ef 관련 툴을 내장하지 않기 때문에, 별도로 설치해야 한다.
다음은 dotnet-ef 를 설치하는 명령이다.
dotnet tool install --global dotnet-ef
다음으로 Command Line 창을 열고, 아래와 같이 dotnet restore, dotnet ef migration add {migration명}, dotnet ef database update 명령을
차례로 실행한다.
여기서 dotnet ef migrations add 명령은 EF Core 모델을 읽어 DB에 적용하기 위해 준비를 하는 과정으로 VS 프로젝트에 Migrations 폴더를 만들고 그 밑에 필요한 C# 코드를
생성한다.
그리고 dotnet ef database update 명령은 DB 서버에 실제 데이타베이스와 테이블을 생성하도록 한다.
참고로 만약 DB와 Table 생성과 관련된 SQL Script를 생성하기 위해서는 아래와 같은 명령을 실행할 수 있다.
dotnet ef migrations script
Package Manager Console에서 Migration을 실행하기 위해서는 Add-Migration 명령과 Update-Database 명령을 실행하면 된다.
Migration은 Code First 모델 클래스가 변경될 때마다 다시 add migration을 실행하고 database update 를 실행하여 DB에 적용할 수 있다.
EF Core Dependancy Injection
EF Core의 DbContext 클래스를 Dependancy Injection으로 사용하기 위해서는
(1) Startup 클래스의 ConfigureServices() 에서 아래와 같이 AddDbContext() 메서드를 호출하여 Dependancy Injection을 사용함을 정의한다.
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
// Step 1. EF DI 및 옵션 지정
string strConn = Configuration["ConnectionStrings:DefaultConnection"];
services.AddDbContext<MyDbContext>((options) =>
{
options.UseSqlServer(strConn);
});
}
특히, 위의 예에서는 DB Connection String을 Configuration 서비스를 통해 읽어 오고 있는데, 이를 위해 appsettings.json 파일에 다음과 같이 Connection
String을 정의하였다.
{
"ConnectionStrings": {
"DefaultConnection": "Server=(local);Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
(2) 다음으로 MyDbContext 클래스이 생성자에 DbContextOptions 파라미터를 아래와 같이 지정한다.
EF Dependancy Injection을 통해 이미 Connection String과 같은 옵션들이 전달되므로 OnConfiguring() 메서드를 지정할 필요는 없다.
그러나 만약 OnConfiguring() 메서드가 지정된다면, 생성자로부터 이미 전달된 옵션들에 추가로 OnConfiguring 메서드에 정의한 옵션들이
더해진다. 만약 동일한 옵션이 있으면 OnConfiguring 옵션이 생성자의 옵션을 Overwrite한다.
// MyDbContext.cs
public class MyDbContext : DbContext
{
// Step 2: DbContextOptions 파리미터 지정해야
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
}
(3) 위와 같이 Dependancy Injection이 셋업되었으면, 프로젝트 안에 있는 임의의 클래스에서 DbContext 객체를 Dependancy Injection으로 얻어올 수 있다.
아래 예제에서 UserController의 생성자는 MyDbContext를 Dependancy Injection Framework 으로부터 얻어오게 된다.
public class UserController : Controller
{
private MyDbContext _db;
// Step 3: 생성자에서 MyDbContext를 Inject 함
public UserController(MyDbContext db)
{
_db = db;
}
public IActionResult View(int id)
{
var usr = _db.Users.SingleOrDefault(p => p.Id == id);
return View(usr);
}
}