다음을 통해 공유


데이터 저장

쿼리를 사용하면 데이터베이스에서 데이터를 읽을 수 있지만, 데이터를 저장하면 데이터베이스에 새 엔터티를 추가하거나, 엔터티를 제거하거나, 어떤 식으로든 기존 엔터티의 속성을 수정할 수 있습니다. EF Core(Entity Framework Core)는 데이터베이스에 데이터를 저장하기 위한 두 가지 기본 방법을 지원합니다.

방법 1: 변경 내용 추적 및 SaveChanges

대부분의 시나리오에서 프로그램은 데이터베이스에서 일부 데이터를 쿼리하고, 일부 수정을 수행하고, 이러한 수정 내용을 다시 저장해야 합니다. 이를 "작업 단위"라고도 합니다. 예를 들어 블로그 집합이 있고, 그 중 하나의 Url 속성을 변경한다고 가정해 보겠습니다. EF에서는 일반적으로 다음과 같이 수행됩니다.

using (var context = new BloggingContext())
{
    var blog = await context.Blogs.SingleAsync(b => b.Url == "http://example.com");
    blog.Url = "http://example.com/blog";
    await context.SaveChangesAsync();
}

위의 코드는 다음 단계를 수행합니다.

  1. 일반 LINQ 쿼리를 사용하여 데이터베이스에서 엔터티를 로드합니다( 쿼리 데이터 참조). EF의 쿼리는 기본적으로 추적되므로 EF는 내부 변경 추적기에서 로드된 엔터티를 추적합니다.
  2. 로드된 엔터티 인스턴스는 .NET 속성을 할당하여 평소와 같이 조작됩니다. EF는 이 단계에 관여하지 않습니다.
  3. 마지막으로 DbContext.SaveChanges()가 호출됩니다. 이 시점에서 EF는 엔터티를 로드한 순간부터 스냅샷과 비교하여 변경 내용을 자동으로 검색합니다. 검색된 모든 변경 내용은 데이터베이스에 유지됩니다. 관계형 데이터베이스를 사용하는 경우 일반적으로 관련 행을 업데이트하기 위해 SQL UPDATE 을 보내는 작업이 포함됩니다.

위에서는 기존 데이터에 대한 일반적인 업데이트 작업을 설명했지만, 추가제거와 같은 엔터티 작업에도 유사한 원칙이 적용됩니다. DbSet<TEntity>.AddRemove을 호출하여 EF의 변경 추적기와 상호작용함으로써 변경 사항을 추적합니다. 그런 다음, EF는 호출될 때 SaveChanges() (예: SQL INSERTDELETE 을 통해 관계형 데이터베이스를 사용하는 경우) 추적된 모든 변경 내용을 데이터베이스에 적용합니다.

SaveChanges() 는 다음과 같은 이점을 제공합니다.

  • 변경된 엔터티 및 속성을 추적하는 코드를 작성할 필요가 없습니다. EF는 자동으로 이 작업을 수행하고 데이터베이스에서 해당 속성만 업데이트하여 성능을 향상합니다. 로드된 엔터티가 UI 구성 요소에 바인딩되어 사용자가 원하는 속성을 변경할 수 있다고 상상해 보세요. EF는 실제로 변경된 엔터티 및 속성을 파악하는 부담을 덜어 깁니다.
  • 데이터베이스 변경 내용을 저장하는 것이 복잡할 수 있습니다. 예를 들어 해당 블로그에 대한 블로그 및 일부 게시물을 추가하려면 게시물을 삽입하기 전에 삽입된 블로그의 데이터베이스 생성 키를 가져와야 할 수 있습니다(블로그를 참조해야 하므로). EF는 이 모든 작업을 수행하여 복잡성을 제거합니다.
  • EF는 데이터베이스 행이 쿼리와 SaveChanges() 사이에 다른 사람에 의해 수정된 경우와 같은 동시성 문제를 감지할 수 있습니다. 자세한 내용은 동시성 충돌에서 확인할 수 있습니다.
  • 이를 지원하는 SaveChanges() 데이터베이스에서 트랜잭션의 여러 변경 내용을 자동으로 래핑하여 오류가 발생할 경우 데이터가 일관성을 유지하도록 합니다. 자세한 내용은 트랜잭션에서 확인할 수 있습니다.
  • SaveChanges() 또한 많은 경우에 여러 변경 내용을 일괄 처리하여 데이터베이스 왕복 횟수를 크게 줄이고 성능을 크게 향상합니다. 자세한 내용은 효율적인 업데이트에서 확인할 수 있습니다.

기본 SaveChanges() 사용에 대한 자세한 내용 및 코드 샘플은 기본 SaveChanges를 참조하세요. EF의 변경 내용 추적에 대한 자세한 내용은 변경 내용 추적 개요를 참조하세요.

방법 2: ExecuteUpdate 및 ExecuteDelete("대량 업데이트")

변경 내용 추적은 SaveChanges() 변경 내용을 저장하는 강력한 방법이지만 특정 단점이 있습니다.

SaveChanges() 먼저 수정하거나 삭제할 모든 엔터티를 쿼리하고 추적해야 합니다. 예를 들어, 특정 임계값보다 낮은 등급의 모든 블로그를 삭제해야 하는 경우, 잠재적으로 방대한 수의 행을 쿼리하고, 구체화하며 추적해야 합니다. 그리고 SaveChanges() 각 행에 대해 DELETE 문을 생성해야 합니다. 관계형 데이터베이스는 훨씬 더 효율적인 대안을 제공합니다. 단일 DELETE 명령을 전송하여 절을 통해 WHERE 삭제할 행을 지정하지만 SaveChanges() 모델은 이를 생성할 수 없습니다.

이 "대량 업데이트" 시나리오를 지원하려면 다음과 같이 사용할 ExecuteDelete 수 있습니다.

context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();

이렇게 하면 일반 LINQ 쿼리와 유사한 일반 LINQ 연산자를 통해 SQL DELETE 문을 표현할 수 있으므로 데이터베이스에 대해 다음 SQL이 실행됩니다.

DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

데이터베이스에서 데이터를 로드하거나 EF의 변경 추적기를 포함하지 않고 데이터베이스에서 매우 효율적으로 실행됩니다. 마찬가지로 ExecuteUpdate SQL UPDATE 문을 표현할 수 있습니다.

엔터티를 대량으로 변경하지 않더라도 변경할 엔터티의 속성을 정확히 알 수 있습니다. 변경 내용 추적 API를 사용하여 변경을 수행하는 것은 지나치게 복잡할 수 있으므로 엔터티 인스턴스를 만들고, 이를 통해 Attach추적하고, 변경하고, 마지막으로 호출 SaveChanges()해야 합니다. 이러한 시나리오의 ExecuteUpdateExecuteDelete 경우 동일한 작업을 표현하는 훨씬 더 간단한 방법이 될 수 있습니다.

마지막으로 변경 내용 추적과 SaveChanges() 자체 모두 특정 런타임 오버헤드를 적용합니다. 고성능 애플리케이션 ExecuteUpdateExecuteDelete 을 작성하는 경우 이러한 구성 요소를 모두 방지하고 원하는 문을 효율적으로 생성할 수 있습니다.

그러나 ExecuteUpdateExecuteDelete 다음과 같은 특정 제한 사항이 있습니다.

  • 이러한 메서드는 즉시 실행되며 현재 다른 작업과 함께 일괄 처리할 수 없습니다. 반면 SaveChanges()에 여러 작업을 함께 일괄 처리할 수 있습니다.
  • 변경 내용 추적은 관련되지 않으므로 변경해야 하는 엔터티와 속성을 정확히 알아야 합니다. 즉, 변경해야 하는 내용과 변경하지 않는 내용을 더 수동적이고 하위 수준 코드로 추적할 수 있습니다.
  • 또한 변경 내용 추적은 포함되지 않으므로 이러한 메서드는 변경 내용을 유지할 때 동시성 제어 를 자동으로 적용하지 않습니다. 하지만, 동시성 제어를 직접 구현하려면 Where 절을 명시적으로 추가할 수 있습니다.
  • 현재 업데이트 및 삭제만 지원되며, 삽입은 DbSet<TEntity>.AddSaveChanges()을(를) 통해 수행해야 합니다.

자세한 내용 및 코드 샘플은 다음을 참조 ExecuteUpdate 하세요 ExecuteDelete.

요약

다음은 어떤 방법을 사용해야 하는 경우에 대한 몇 가지 지침입니다. 절대 규칙은 아니지만 유용한 규칙을 제공합니다.

  • 어떤 변경이 수행될지 미리 모르는 경우 사용 SaveChanges하세요. 적용해야 하는 변경 내용을 자동으로 검색합니다. 예제 시나리오:
    • "데이터베이스에서 블로그를 로드하고 사용자가 변경할 수 있는 양식을 표시하려고 합니다."
  • 개체 그래프(예: 여러 상호 연결된 개체)를 조작해야 하는 경우 다음을 사용합니다 SaveChanges. 변경 내용의 적절한 순서와 모든 항목을 함께 연결하는 방법을 파악합니다.
    • "블로그를 업데이트하고, 일부 게시물을 변경하고, 다른 게시물을 삭제하고 싶습니다."
  • 일부 기준에 따라 잠재적으로 많은 수의 엔터티를 변경하려면 다음을 사용합니다 ExecuteUpdateExecuteDelete. 예제 시나리오:
    • 모든 직원에게 급여 인상을 주고 싶습니다.
    • "이름이 X로 시작하는 모든 블로그를 삭제하려고 합니다."
  • 수정하려는 엔터티와 해당 엔터티를 변경하는 방법을 이미 알고 있는 경우 사용 ExecuteUpdateExecuteDelete. 예제 시나리오:
    • "이름이 'Foo'인 블로그를 삭제하려고 합니다."
    • "ID가 5인 블로그의 이름을 'Bar'로 변경하려고 합니다."