Coding Memo
Entity Framework - virtual 키워드 본문
Entity Framework에서 데이터 모델 클래스를 작성할 때, Navigation Property (네비게이션 속성)에 virtual 키워드를 붙일 수 있다.
virtual 키워드는 Entity Framework가 이 속성(property)를 Lazy Loading 하도록 한다.
Lazy Loading은 해당 클래스나 객체를 로드시에 같이 바로 로드되는 것이 아니라, 관련된 데이터가 실제로 필요한 시점에만 데이터베이스로부터 로드하도록 한다.
아래와 같은 모델이 있다고 사정하자.
[Table("User")]
public class UserDb {
[Key]
public ulong UserId { get; set; }
public string UserName { get; set; }
}
[Table("Room")]
public class RoomDb {
[Key]
public ulong RoomId { get; set; }
public virtual ICollection<UserDb> Users { get; set; }
}
예를 들어 위 데이터모델에서, RoomDb는 로드 시에 RoomId만을 로드한다. 이때 추가적인 로드가 없다면 Users는 null 값으로 로드된다.
virtual 속성 로드 방법
Linq의 Include를 사용하여 로드시 포함시킨다.
using (AppDbContext db = new AppDbContext())
{
// find room
RoomDb room = db.Rooms
.Include(r => r.Users)
.FirstOrDefault();
// room에 있는 Users 관련 작업 가능
}
include를 이용하지 않고 단순히 로드한다면 virtual로 지정된 속성은 로드가 되지 않고 null값이 들어가 있는 것을 볼 수 있을 것이다.
테스트 코드
AppDbContext
public class AppDbContext : DbContext
{
const string ConnString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Test;Integrated Security=True;Connect Timeout=30;Encrypt=False;Trust Server Certificate=False;Application Intent=ReadWrite;Multi Subnet Failover=False";
public DbSet<UserDb> Users { get; set; }
public DbSet<RoomDb> Rooms { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConnString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserDb>()
.HasIndex(u => u.UserName)
.IsUnique();
}
}
Model
[Table("User")]
public class UserDb
{
[Key]
public ulong UserId { get; set; }
public string UserName { get; set; }
}
[Table("Room")]
public class RoomDb
{
[Key]
public ulong RoomId { get; set; }
public virtual ICollection<UserDb> Users { get; set; }
}
Main
class Program
{
static void Main()
{
using (AppDbContext db = new AppDbContext())
{
// add data codes
//db.Rooms.Add(
// new()
// {
// RoomId = 1,
// Users = new[]
// {
// new UserDb() { UserId = 1, UserName = "Test1" },
// new UserDb() { UserId = 2, UserName = "Test2" },
// new UserDb() { UserId = 3, UserName = "Test3" }
// }
// });
//db.SaveChanges();
// 해당 코드는 room의 Users를 로드하지 않음 => null
//RoomDb room = db.Rooms
// .FirstOrDefault(r => r.RoomId == 1);
RoomDb room = db.Rooms
.Include(r => r.Users)
.FirstOrDefault(r => r.RoomId == 1);
// room에 있는 Users 관련 작업 가능
if (room.Users == null) // include 하지 않았을 경우
{
Console.WriteLine("The Users in room is not loaded. [room.Users == null]");
}
else
{
foreach (var user in room.Users)
{
Console.WriteLine(user.UserName);
}
}
}
}
}
'Language > C#' 카테고리의 다른 글
Http에서의 Json Convert - nullable (1) | 2024.02.05 |
---|---|
라이브러리 xml 문서 생성 (API Documentation) (0) | 2024.01.30 |
BitConverter, 직렬화 (little-endian, big-endian) (0) | 2023.12.06 |
Environment.TickCount 오버플로우 (대안) (0) | 2023.11.29 |
싱글턴 멀티 스레드 주의 (1) | 2023.11.23 |