Entity Framework Core(EFC)는 .NET Core
와 .NET 5
버전 이상에서 사용가능한 ORM 프레임워크로 코드로 데이터베이스 생성, 테이블 생성과 같은 데이터베이스 작업을 수행할 수 있다. 이 외에도 DB Migration으로 데이터베이스 스키마를 버전 관리할 수 있다.
EFC를 C#프로젝트에서 사용하기 위해 NuGet패키지 관리자로 아래 사진과 같은 패키지를 설치해야 한다.
데이터베이스에서 Table이 될 Entity를 하나의 클래스로 나타낼 수 있다. [Table("Item")]
와 같은 어트리뷰트로 데이터베이스가 생성될 때의 테이블 이름을 지정할 수 있으며 Entity간의 참조형식도 지정할 수 있다.
[Table("Item")]
public class Item
{
public int ItemId { get; set; }
public int TemplateId { get; set; }
public DateTime CreateData { get; set; }
public int OwnerId { get; set; }
public Player Owner { get; set; }
}
public class Player
{
public int PlayerId { get; set; }
public string Name { get; set; }
}
public int 클래스이름+Id
형식의 컬럼은 해당 테이블의 PK(Primary Key)로 설정된다. 또한 Item을 보면 Item은 Owner라는 이름으로 Player Entity를 참조하고 public int OwnerId
라는 프로퍼티가 있으므로 OwnerId
는 FK(Foreign Key)로 설정된다.
실제 코드에서 데이터베이스를 사용하기 위한 클래스는 DbContext를 상속받아 해당 클래스를 사용해 코드에서 테이블로 접근할 수 있다.
DbSet<Item>
은 외부에서 테이블을 접근하기 위한 수단을 제공하며 OnConfiguring와 같은 On계열 함수는 데이터베이스 연결, 데이터베이스 생성, 데이터베이스 모델생성 단계에서 추가적으로 설정하고자 하는 내용을 반영할 수 있도록 한다.
public class AppDbContext : DbContext
{
public DbSet<Item> Items { get; set; }
public const string connectionString = "";
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(connectionString);
}
}
EFC를 이용해 특정 Entity에 대한 CRUD를 구현할 수 있다. 이때 데이터베이스의 테이블에 질의한 결과를 얻기 위해서는 앞서 정의한 DbContext의 하위클래스의 DbSet을 통해 할 수 있다.
Create연산은 생성하고자 하는 Entity 클래스를 생성한 뒤 DbContext의 Add함수로 추가할 수 있다.
using (var db = new AppDbContext())
{
var player = new Player { Name = "Seoki" };
db.Add(player);
db.SaveChanges();
}
여러개의 Entity를 추가하기 위해서는 AddRange를 사용할 수 있다.
Read연산은 Where함수를 통해 특정 조건을 만족하는 데이터를 필터링할 수 있고 매개변수로는 조건에 해당하는 LINQ 쿼리를 넣어주어야 한다.
using (var db = new AppDbContext())
{
var items = db.Items
.Where(i => i.OwnerId == player.PlayerId)
.ToList();
foreach (var item in items)
{
Console.WriteLine($"{item.ItemId}");
}
}
PK를 이용해 단일 Entity를 검색할 때는 Find함수를, LINQ 쿼를 이용해 단일 Entity를 검색할 때는 Single, First를 사용할 수 있다.
Update는 찾은 Entity의 값을 변경한 뒤 SaveChange를 통해 데이터베이스로 변경사항을 적용함으로 구현할 수 있다.
string name = "Seoki";
using (var db = new AppDbContext())
{
var items = db.Items.Include(i => i.Owner)
.Where(i => i.Owner.Name == name);
foreach(Item item in items)
{
item.CreateData = DateTime.Now;
}
db.SaveChanges();
}
Update과정에서 사용한 Include는 Entity구조의 Item에서 참조하는 Player의 값을 가져오기 위한 함수이다.
공식문서를 찾아보니 Include는 EFC에서 Navigation Property를 로딩하기 위한 함수라고 한다. 이것은 'Eager Loading'이라고 하며 이를 통해
N+1문제
를 방지할 수 있다.
Delete는 찾은 Entity를 DbContext의 Remove함수의 인자로 넘겨 해당 데이터를 삭제하겠다는 사항을 알리고 SaveChanges를 이용해 데이터베이스에 반영하는 방법으로 구현할 수 있다.
string name = "Seoki";
using (var db = new AppDbContext())
{
var items = db.Items.Include(i => i.Owner)
.Where(i => i.Owner.Name == name);
db.Items.RemoveRange(items);
db.SaveChanges();
}
Delete 역시 여러개의 데이터를 삭제하려면 RemoveRange함수를 사용할 수 있다.