하위 삭제

EF Core(Entity Framework Core)는 외래 키를 사용하여 관계를 나타냅니다. 외래 키가 있는 엔터티는 관계에서 자식 또는 종속 엔터티입니다. 해당 엔터티의 외래 키 값은 관련 보안 주체/부모 엔터티의 기본 키 값(또는 대체 키 값)과 일치해야 합니다.

보안 주체/부모 엔터티가 삭제되면 종속 항목/자식의 외래 키 값이 더 이상 ‘모든’ 보안 주체.부모의 기본 또는 대체 키와 일치하지 않습니다. 이는 잘못된 상태이며 대부분 데이터베이스에서 참조 제약 조건 위반을 초래합니다.

해당 참조 제약 조건 위반을 방지하는 두 가지 옵션이 있습니다.

  1. FK 값을 null로 설정
  2. 종속/자식 엔터티도 삭제

첫 번째 옵션은 외래 키 속성(및 해당 속성이 매핑되는 데이터베이스 열)이 null을 허용해야 하는 선택적 관계에만 유효합니다.

두 번째 옵션은 모든 종류의 관계에 유효하며 “하위 삭제”라고 합니다.

이 문서에서는 데이터베이스 업데이트 관점에서 하위 삭제(및 고아 삭제)를 설명합니다. 문서에서는 EF Core의 변경 내용 추적외래 키 및 탐색 변경에 도입된 개념을 많이 사용합니다. 여기에서 자료를 살펴보기 전에 관련 개념을 완전히 이해해야 합니다.

GitHub에서 샘플 코드를 다운로드하여 이 문서의 모든 코드를 실행하고 디버그할 수 있습니다.

계단식 배열 동작이 발생하는 경우

종속/자식 엔터티를 현재 보안 주체/부모 엔터티와 더 이상 연결할 수 없는 경우 하위 삭제가 필요합니다. 해당 문제는 보안 주체/부모가 삭제되거나 보안 주체/부모가 존재하지만 종속 항목/자식이 더 이상 연결되지 않기 때문에 발생할 수 있습니다.

보안 주체/부모 삭제

종속 항목/자식인 Post와 관계에서 Blog가 보안 주체/부모인 간단한 모델을 살펴봅니다. Post.BlogId는 외래 키 속성이며, 해당 값은 게시물이 속한 블로그의 Blog.Id 기본 키와 일치해야 합니다.

public class Blog
{
    public int Id { get; set; }

    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }

    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

규칙에 따라 Post.BlogId 외래 키 속성이 null을 허용하지 않기 때문에 이 관계는 필수로 구성됩니다. 필수 관계는 기본적으로 하위 삭제를 사용하도록 구성됩니다. 관계 모델링에 관한 자세한 내용은 관계를 참조하세요.

블로그를 삭제하면 모든 게시물이 하위 삭제됩니다. 예를 들면 다음과 같습니다.

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

context.Remove(blog);

context.SaveChanges();

SaveChanges는 SQL Server를 예로 사용하여 다음 SQL을 생성합니다.

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

관계 단절

블로그를 삭제하는 대신, 각 게시물과 해당 블로그 간 관계를 단절할 수 있습니다. 이렇게 하려면 각 게시물에서 참조 탐색 Post.Blog를 null로 설정합니다.

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

context.SaveChanges();

Blog.Posts 컬렉션 탐색에서 각 게시물을 제거하여 관계를 단절할 수도 있습니다.

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

blog.Posts.Clear();

context.SaveChanges();

어느 경우에나 결과는 동일합니다. 블로그는 삭제되지 않지만 블로그와 더 이상 연결되지 않는 게시물은 삭제됩니다.

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

더 이상 보안 주체/종속 항목과 연결되지 않는 엔터티를 삭제하는 작업을 “고아 삭제”라고 합니다.

하위 삭제 및 고아 삭제는 밀접하게 관련되어 있습니다. 두 작업은 모두 필수 보안 주체/부모에 대한 관계가 단절될 때 종속/자식 엔터티를 삭제합니다. 하위 삭제의 경우 보안 주체/부모 자체가 삭제되기 때문에 해당 단절이 발생합니다. 고아의 경우 보안 주체/부모 엔터티는 여전히 존재하지만 더 이상 종속/자식 엔터티와 관련되지 않습니다.

계단식 배열 동작이 발생하는 경우

계단식 배열 동작을 적용할 수 있는 대상:

  • 현재 DbContext가 추적하는 엔터티
  • 컨텍스트에 로드되지 않은 데이터베이스의 엔터티

추적된 엔터티의 하위 삭제

EF Core는 항상 구성된 계단식 배열 동작을 추적된 엔터티에 적용합니다. 즉, 위의 예제와 같이 애플리케이션이 모든 관련 종속/자식 엔터티를 DbContext에 로드하면 데이터베이스 구성 방법과 관계없이 계단식 배열 동작이 제대로 적용됩니다.

추적된 엔터티에 대해 계단식 배열 동작이 수행되는 정확한 타이밍은 ChangeTracker.CascadeDeleteTimingChangeTracker.DeleteOrphansTiming을 사용하여 제어할 수 있습니다. 자세한 내용은 외래 키 및 탐색 변경을 참조하세요.

데이터베이스의 하위 삭제

또한 많은 데이터베이스 시스템은 데이터베이스에서 엔터티가 삭제될 때 트리거되는 계단식 배열 동작을 제공합니다. EF Core는 EnsureCreated 또는 EF Core를 사용하여 데이터베이스를 만들 때 EF Core 모델의 하위 삭제 동작에 따라 계단식 배열 동작을 구성합니다. 예를 들어 위의 모델을 사용하면 SQL Server를 사용할 때 게시물에 관한 다음 테이블이 생성됩니다.

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    [BlogId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]) ON DELETE CASCADE
);

블로그와 게시물 간 관계를 정의하는 외래 키 제약 조건은 ON DELETE CASCADE를 사용하여 구성됩니다.

데이터베이스가 이와 같이 구성된 것을 알고 있으면 ‘게시물을 먼저 로드하지 않고’ 블로그를 삭제할 수 있으며 데이터베이스는 해당 블로그와 관련된 모든 게시물을 삭제합니다. 예를 들면 다음과 같습니다.

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).First();

context.Remove(blog);

context.SaveChanges();

게시물에 대한 Include가 없으므로 게시물이 로드되지 않습니다. 이 경우 SaveChanges는 추적되는 유일한 엔터티인 블로그만 삭제합니다.

-- Executed DbCommand (6ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

이로 인해 데이터베이스의 외래 키 제약 조건이 하위 삭제로 구성되지 않으면 예외가 발생합니다. 그러나, 이 경우 데이터베이스를 만들 때 ON DELETE CASCADE를 사용하여 데이터베이스를 구성했기 때문에 데이터베이스가 게시물을 삭제합니다.

참고

일반적으로 데이터베이스는 고아를 자동으로 삭제할 필요가 없습니다. 그 이유는 EF Core는 외래 키 및 탐색을 사용하여 관계를 나타내지만, 데이터베이스에는 외래 키만 있고 탐색이 없기 때문입니다. 즉, DbContext에 양쪽을 모두 로드하지 않으면 일반적으로 관계를 단절할 수 없습니다.

참고

EF Core 메모리 내 데이터베이스는 현재 데이터베이스의 하위 삭제를 지원하지 않습니다.

경고

엔터티를 일시 삭제할 경우에는 데이터베이스에서 하위 삭제를 구성하지 않아야 합니다. 이로 인해 엔터티가 일시 삭제되는 것이 아니라 실수로 실제로 삭제될 수 있습니다.

데이터베이스 계단식 배열 제한 사항

일부 데이터베이스, 특히 SQL Server에는 주기를 형성하는 계단식 배열 동작에 관한 제한 사항이 있습니다. 예를 들어 다음 모델을 살펴봅니다.

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();

    public int OwnerId { get; set; }
    public Person Owner { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }

    public int AuthorId { get; set; }
    public Person Author { get; set; }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();

    public Blog OwnedBlog { get; set; }
}

이 모델에는 세 가지 관계가 있고 모두 필수 관계이므로 규칙에 따라 하위 삭제되도록 구성됩니다.

  • 블로그를 삭제하면 모든 관련 게시물이 하위 삭제됩니다.
  • 게시물의 작성자를 삭제하면 작성된 게시물이 하위 삭제됩니다.
  • 블로그의 소유자를 삭제하면 해당 블로그가 하위 삭제됩니다.

이는 모두 합리적이지만(블로그 관리 정책에서는 약간 가혹함) 이와 같은 계단식 배열이 구성된 SQL Server 데이터베이스를 만들려고 하면 다음 예외가 발생합니다.

Microsoft.Data.SqlClient.SqlException(0x80131904): 테이블 ‘Posts’에 FOREIGN KEY 제약 조건 ‘FK_Posts_Person_AuthorId’를 사용하면 경로가 순환하거나 여러 경로가 중첩될 수 있습니다. ON DELETE NO ACTION 또는 ON UPDATE NO ACTION을 지정하거나 다른 FOREIGN KEY 제약 조건을 수정하십시오.

해당 상황을 처리하는 방법에는 두 가지가 있습니다.

  1. 하위 삭제되지 않도록 하나 이상의 관계를 변경합니다.
  2. 하위 삭제 중 하나 이상을 사용하지 않고 데이터베이스를 구성한 다음, EF Core가 계단식 배열 동작을 수행할 수 있도록 모든 종속 엔터티를 로드해야 합니다.

예제에서 첫 번째 방법을 사용하면 nullable 외래 키 속성을 제공하여 블로그 후 관계를 선택적으로 만들 수 있습니다.

public int? BlogId { get; set; }

선택적 관계에서는 게시글이 블로그 없이 존재할 수 있습니다. 즉, 더 이상 하위 삭제가 기본적으로 구성되지 않습니다. 이는 계단식 배열 동작에 더 이상 순환이 없으며 SQL Server에서 오류 없이 데이터베이스를 만들 수 있음을 의미합니다.

대신 두 번째 방법을 사용하면, 계속해서 블로그-소유자 관계를 필수로 설정하고 하위 삭제를 사용하도록 구성할 수 있지만 해당 구성은 데이터베이스가 아니라 추적된 엔터티에만 적용됩니다.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

이제 사용자와 사용자가 소유한 블로그를 둘 다 로드한 후 사용자를 삭제하면 어떻게 되나요?

using var context = new BlogsContext();

var owner = context.People.Single(e => e.Name == "ajcvickers");
var blog = context.Blogs.Single(e => e.Owner == owner);

context.Remove(owner);

context.SaveChanges();

EF Core는 소유자 삭제를 계단식으로 처리하므로 블로그도 삭제됩니다.

-- Executed DbCommand (8ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [People]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

그러나 소유자가 삭제될 때 블로그가 로드되지 않은 경우에는:

using var context = new BlogsContext();

var owner = context.People.Single(e => e.Name == "ajcvickers");

context.Remove(owner);

context.SaveChanges();

데이터베이스의 외래 키 제약 조건 위반으로 인해 예외가 throw됩니다.

Microsoft.Data.SqlClient.SqlException: DELETE 문이 REFERENCE 제약 조건 “FK_Blogs_People_OwnerId”와 충돌합니다. 데이터베이스 “Scratch”, 테이블 “dbo.Blogs”, 열 ‘OwnerId’에서 충돌이 발생했습니다. 문이 종료되었습니다.

계단식 배열 null

선택적 관계에서는 null 허용 외래 키 속성이 null 허용 데이터베이스 열에 매핑됩니다. 즉, 현재 보안 주체/부모가 삭제되거나 종속 항목/자식에서 단절되는 경우 외래 키 값을 null로 설정할 수 있습니다.

계단식 배열 동작이 발생하는 경우의 예제를 다시 살펴보겠습니다. 하지만 이번에는 null 허용 Post.BlogId 외래 키 속성으로 선택적 관계를 나타냅니다.

public int? BlogId { get; set; }

해당 외래 키 속성은 관련된 블로그가 삭제될 때 각 게시물에 대해 null로 설정됩니다. 예를 들어 이전과 동일한 해당 코드는:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

context.Remove(blog);

context.SaveChanges();

이제 SaveChanges가 호출될 때 다음 데이터베이스 업데이트를 수행합니다.

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (1ms) [Parameters=[@p2='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p2;
SELECT @@ROWCOUNT;

마찬가지로, 위의 예제 중 하나를 사용하여 관계가 단절되는 경우에는:

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

context.SaveChanges();

또는

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

blog.Posts.Clear();

context.SaveChanges();

SaveChanges가 호출될 때 null 외래 키 값을 사용하여 게시물이 업데이트됩니다.

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

값이 변경될 때 EF Core가 외래 키 및 탐색을 관리하는 방법에 관한 자세한 내용은 외래 키 및 탐색 변경을 참조하세요.

참고

이와 같은 관계 수정은 2008년 첫 번째 버전 이후 Entity Framework의 기본 동작이었습니다. EF Core 이전에는 이름이 없었고 변경할 수 없었습니다. 이제 해당 수정은 다음 섹션에서 설명하는 것처럼 ClientSetNull이라고 합니다.

선택적 관계의 보안 주체/부모가 삭제될 때 이와 같이 null을 계단식으로 처리하도록 데이터베이스를 구성할 수도 있습니다. 그러나 이 방법은 데이터베이스에서 하위 삭제를 사용하는 것보다 일반적이지 않습니다. 데이터베이스에서 하위 삭제 및 계단식 배열 null을 동시에 사용하면 SQL Server를 사용할 때 거의 항상 관계 순환이 발생합니다. 계단식 배열 null 구성에 관한 자세한 내용은 다음 섹션을 참조하세요.

계단식 배열 동작 구성

진행하기 전에 먼저 위의 섹션을 읽어 보아야 합니다. 위의 자료를 이해하지 못했다면 구성 옵션이 이해되지 않을 수 있습니다.

계단식 배열 동작은 OnModelCreating에서 OnDelete 메서드를 사용하여 관계별로 구성됩니다. 예를 들면 다음과 같습니다.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

엔터티 형식 간 관계 구성에 관한 자세한 내용은 관계를 참조하세요.

OnDelete는 명백하게 혼란스러운 DeleteBehavior 열거형의 값을 허용합니다. 해당 열거형은 추적된 엔터티의 EF Core 동작 및 EF를 사용하여 스키마를 만들 때 데이터베이스의 하위 삭제 구성을 둘 다 정의합니다.

데이터베이스 스키마에 미치는 영향

다음 표에서는 EF Core 마이그레이션 또는 EnsureCreated에서 만든 외래 키 제약 조건에 따른 각 OnDelete 값의 결과를 보여 줍니다.

DeleteBehavior 데이터베이스 스키마에 미치는 영향
계단식 배열 ON DELETE CASCADE
제한 ON DELETE RESTRICT
NoAction 데이터베이스 기본
SetNull ON DELETE SET NULL
ClientSetNull 데이터베이스 기본
ClientCascade 데이터베이스 기본
ClientNoAction 데이터베이스 기본

관계형 데이터베이스에서 ON DELETE NO ACTION(데이터베이스 기본값) 및 ON DELETE RESTRICT의 동작은 일반적으로 동일하거나 매우 유사합니다. NO ACTION의 가능한 의미와는 다르게 해당 옵션은 둘 다 참조 제약 조건을 적용합니다. 한 가지 차이점은 데이터베이스가 제약 조건을 확인할 ‘때’입니다. ON DELETE NO ACTIONON DELETE RESTRICT 간 특정 차이점에 관해서는 데이터베이스 설명서를 참조하세요.

SQL Server에서 ON DELETE RESTRICT를 지원하지 않으므로 ON DELETE NO ACTION이 대신 사용됩니다.

데이터베이스에서 계단식 배열 동작을 초래하는 유일한 값은 CascadeSetNull입니다. 다른 모든 값은 변경 내용을 계단식으로 처리하지 않도록 데이터베이스를 구성합니다.

SaveChanges 동작에 미치는 영향

다음 섹션의 표에서는 보안 주체/부모가 삭제되거나 종속/자식 엔터티에 대한 관계가 단절되는 경우 종속/자식 엔터티에 수행되는 작업을 다룹니다. 각 표는 다음 중 하나를 다룹니다.

  • 선택적(null 허용 FK) 및 필수(null을 허용하지 않는 FK) 관계
  • DbContext에서 종속 항목/자식을 로드하고 추적하는 경우 및 종속 항목/자식이 데이터베이스에만 있는 경우

로드되는 종속 항목/자식과 필수 관계

DeleteBehavior 보안 주체/부모 삭제 시 보안 주체/부모에서 단절 시
계단식 배열 EF Core에서 삭제된 종속 항목 EF Core에서 삭제된 종속 항목
제한 InvalidOperationException InvalidOperationException
NoAction InvalidOperationException InvalidOperationException
SetNull 데이터베이스를 만들 때 SqlException 데이터베이스를 만들 때 SqlException
ClientSetNull InvalidOperationException InvalidOperationException
ClientCascade EF Core에서 삭제된 종속 항목 EF Core에서 삭제된 종속 항목
ClientNoAction DbUpdateException InvalidOperationException

참고:

  • 이와 같은 필수 관계의 기본값은 Cascade입니다.
  • 필수 관계에 하위 삭제 이외의 작업을 사용하면 SaveChanges가 호출될 때 예외가 발생합니다.
    • 일반적으로 해당 예외는 로드된 자식/종속 항목에서 잘못된 상태가 검색되기 때문에 EF Core에서 발생하는 InvalidOperationException입니다.
    • ClientNoAction은 수정 종속 항목을 데이터베이스에 보내기 전에 EF Core가 수정 종속 항목을 강제로 확인하지 않도록 하므로, 이 경우 데이터베이스는 예외를 throw하고 이후 해당 예외는 SaveChanges에 의해 DbUpdateException으로 래핑됩니다.
    • SetNull은 외래 키 열이 null을 허용하지 않기 때문에 데이터베이스를 만들 때가 거부됩니다.
  • 종속 항목/자식은 로드되므로 항상 EF Core에 의해 삭제되며 데이터베이스가 삭제될 때 남아 있지 않습니다.

로드되지 않는 종속 항목/자식과 필수 관계

DeleteBehavior 보안 주체/부모 삭제 시 보안 주체/부모에서 단절 시
계단식 배열 데이터베이스에서 삭제된 종속 항목 N/A
제한 DbUpdateException N/A
NoAction DbUpdateException N/A
SetNull 데이터베이스를 만들 때 SqlException N/A
ClientSetNull DbUpdateException N/A
ClientCascade DbUpdateException N/A
ClientNoAction DbUpdateException N/A

참고:

  • 종속 항목/자식이 로드되지 않기 때문에 여기서는 관계 단절이 유효하지 않습니다.
  • 이와 같은 필수 관계의 기본값은 Cascade입니다.
  • 필수 관계에 하위 삭제 이외의 작업을 사용하면 SaveChanges가 호출될 때 예외가 발생합니다.
    • 일반적으로 해당 예외는 종속 항목/자식이 로드되지 않을 뿐 아니라 데이터베이스만 잘못된 상태를 검색할 수 있기 때문에 DbUpdateException입니다. 이후 SaveChanges는 데이터베이스 예외를 DbUpdateException으로 래핑합니다.
    • SetNull은 외래 키 열이 null을 허용하지 않기 때문에 데이터베이스를 만들 때가 거부됩니다.

로드되는 종속 항목/자식과 선택적 관계

DeleteBehavior 보안 주체/부모 삭제 시 보안 주체/부모에서 단절 시
계단식 배열 EF Core에서 삭제된 종속 항목 EF Core에서 삭제된 종속 항목
제한 EF Core에서 null로 설정된 종속 FK EF Core에서 null로 설정된 종속 FK
NoAction EF Core에서 null로 설정된 종속 FK EF Core에서 null로 설정된 종속 FK
SetNull EF Core에서 null로 설정된 종속 FK EF Core에서 null로 설정된 종속 FK
ClientSetNull EF Core에서 null로 설정된 종속 FK EF Core에서 null로 설정된 종속 FK
ClientCascade EF Core에서 삭제된 종속 항목 EF Core에서 삭제된 종속 항목
ClientNoAction DbUpdateException EF Core에서 null로 설정된 종속 FK

참고:

  • 이와 같은 선택적 관계의 기본값은 ClientSetNull입니다.
  • Cascade 또는 ClientCascade가 구성되지 않는 경우에는 종속 항목/자식이 삭제되지 않습니다.
  • 다른 모든 값을 사용하면 EF Core에서 종속 FK를 null로 설정합니다.
    • ...단, ClientNoAction은 보안 주체/부모가 삭제될 때 종속 항목/자식의 외래 키를 변경하지 않도록 EF Core에 알립니다. 따라서 데이터베이스는 SaveChanges에 의해 DbUpdateException으로 래핑되는 예외를 throw합니다.

로드되지 않는 종속 항목/자식과 선택적 관계

DeleteBehavior 보안 주체/부모 삭제 시 보안 주체/부모에서 단절 시
계단식 배열 데이터베이스에서 삭제된 종속 항목 N/A
제한 DbUpdateException N/A
NoAction DbUpdateException N/A
SetNull 데이터베이스에서 null로 설정된 종속 FK N/A
ClientSetNull DbUpdateException N/A
ClientCascade DbUpdateException N/A
ClientNoAction DbUpdateException N/A

참고:

  • 종속 항목/자식이 로드되지 않기 때문에 여기서는 관계 단절이 유효하지 않습니다.
  • 이와 같은 선택적 관계의 기본값은 ClientSetNull입니다.
  • 데이터베이스가 삭제 또는 null을 계단식으로 처리하도록 구성되는 경우가 아니면 데이터베이스 예외를 방지하기 위해 종속 항목/자식을 로드해야 합니다.