-
EF CORE의 상태 변경프로그래밍 2024. 10. 16. 11:24
EF CORE에서 중요한 것 중 하나는 Tracking, 즉, 상태 추적이다.
EF CORE의 Entity는 상태 추적을 비활성화하지 않는 이상에는 모두 상태를 추적하게 되어 있다.
따라서, Entity는 조회, 삽입, 수정, 삭제에 대한 추적 마킹을 가지고 다닌다고 생각하면 되겠다.
해당 마킹 타입은 아래와 같다.
public enum EntityState { /// <summary>The entity is not being tracked by the context.</summary> Detached, /// <summary> /// The entity is being tracked by the context and exists in the database. Its property /// values have not changed from the values in the database. /// </summary> Unchanged, /// <summary> /// The entity is being tracked by the context and exists in the database. It has been marked /// for deletion from the database. /// </summary> Deleted, /// <summary> /// The entity is being tracked by the context and exists in the database. Some or all of its /// property values have been modified. /// </summary> Modified, /// <summary> /// The entity is being tracked by the context but does not yet exist in the database. /// </summary> Added, }
Detached는 상태가 없는, 즉, Entity를 new로 생성한 시점이나 remove 한 시점의 상태이다.
Unchanged는 조회한 시점.
Deleted는 삭제된 시점.
Modified는 수정된 시점
Added는 추가된 시점이다.
여기서 한 가지 중요한 것은 Unchanged와 Modified이겠다.
아래의 코드를 보자.
// 2. 엔티티가 Modified 상태일 때 (수정) var existingUser = await dbContext.Users.FirstAsync(); existingUser.Name = "Updated User"; // 속성 변경 Console.WriteLine($"Existing User State: {dbContext.Entry(existingUser).State}"); // 출력: Modified await dbContext.SaveChangesAsync(); // UPDATE 실행 Console.WriteLine($"Existing User State after Save: {dbContext.Entry(existingUser).State}"); // 출력: Unchanged
위 코드에서 기존 내역을 조회하고 있고 Name을 변경한 상태이다. 변경한 시점에 Entity의 상태는 Modified가 되며
SaveChangesAsync를 호출하는 시점에 아래의 쿼리가 생성된다.
update User set Name = @p1 where Id = @p2
즉, 상태에 따라 insert, update, delete가 수행되는 것이다.
따라서 EF CORE는 각 엔티티의 상태 추적에 따라 SQL 문을 생성하여 실행하는 것이다.
만약, 조회한 데이터 중 상태 추적을 강제로 변경하고 싶다면 아래의 코드처럼 하면 된다.
// 상태를 직접 변경 dbContext.Entry(detachedUser).State = EntityState.Modified; // 추적 상태를 Modified로 변경 Console.WriteLine($"Detached User State after Modification: {dbContext.Entry(detachedUser).State}"); // 출력: Modified
EF CORE를 사용할 때 Master-Detail을 한 번에 처리할 경우 Master를 입력하고 채번 된 PK를 Detail의 FK에 삽입할 때 중복 오류가 발생할 수 있는데, 이때 위와 같이 상태를 직접 변경해도 된다.
아래는 상태 추적에 대한 전체 예제이다.
using System; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; public class AppDbContext : DbContext { public DbSet<User> Users { get; set; } // InMemory Database 설정 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseInMemoryDatabase("TestDatabase"); } } public class User { public int Id { get; set; } public string Name { get; set; } } public class Program { public static async Task Main(string[] args) { using var dbContext = new AppDbContext(); // 1. 엔티티가 Added 상태일 때 (추가) var newUser = new User { Name = "New User" }; dbContext.Users.Add(newUser); Console.WriteLine($"New User State: {dbContext.Entry(newUser).State}"); // 출력: Added await dbContext.SaveChangesAsync(); // INSERT 실행 Console.WriteLine($"New User State after Save: {dbContext.Entry(newUser).State}"); // 출력: Unchanged (SaveChanges 후 상태 변경) // 2. 엔티티가 Modified 상태일 때 (수정) var existingUser = await dbContext.Users.FirstAsync(); existingUser.Name = "Updated User"; // 속성 변경 Console.WriteLine($"Existing User State: {dbContext.Entry(existingUser).State}"); // 출력: Modified await dbContext.SaveChangesAsync(); // UPDATE 실행 Console.WriteLine($"Existing User State after Save: {dbContext.Entry(existingUser).State}"); // 출력: Unchanged // 3. 엔티티가 Deleted 상태일 때 (삭제) dbContext.Users.Remove(existingUser); // 삭제 예정으로 설정 Console.WriteLine($"Deleted User State: {dbContext.Entry(existingUser).State}"); // 출력: Deleted await dbContext.SaveChangesAsync(); // DELETE 실행 Console.WriteLine($"Deleted User State after Save: {dbContext.Entry(existingUser).State}"); // 출력: Detached (삭제 후 추적 종료) // 4. Detached 상태 (추적되지 않음) var detachedUser = new User { Id = 1, Name = "Detached User" }; Console.WriteLine($"Detached User State: {dbContext.Entry(detachedUser).State}"); // 출력: Detached (추적되지 않음) // 상태를 직접 변경 dbContext.Entry(detachedUser).State = EntityState.Modified; // 추적 상태를 Modified로 변경 Console.WriteLine($"Detached User State after Modification: {dbContext.Entry(detachedUser).State}"); // 출력: Modified await dbContext.SaveChangesAsync(); // UPDATE 실행 } }
마지막 상태를 직접 변경하는 부분에서 오류가 발생하는 부분을 확인해 보면 확실히 이해할 수 있을 것이다.
위 코드 실행을 위해서는 아래의 패키지가 필요하다.
Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.InMemory
도움이 되기를 바라며.
'프로그래밍' 카테고리의 다른 글
ASP.NET CORE에서의 JWT 처리 (0) 2024.10.16 SignalR Redis Backplane (0) 2024.10.16 예약, 예매 시스템에 대한 고찰-2 (6) 2024.10.16 Entity Framework는 Unit of Work가 필요한가? (0) 2024.10.14 멀티스레드 환경에서의 데이터 전송에 대한 안정성 향상 방법 (3) 2024.10.10