일대일 관계
일대일 관계는 한 엔터티가 최대 하나의 다른 엔터티와 연결된 경우에 사용됩니다. 예를 들어 Blog
에 하나의 BlogHeader
가 있으며 해당 BlogHeader
는 단일 Blog
에 속합니다.
이 문서는 많은 예제를 중심으로 구성되어 있습니다. 예제는 개념도 소개하는 일반적인 사례로 시작합니다. 이후 예제에서는 덜 일반적인 구성 종류를 다룹니다. 여기서 좋은 방법은 처음 몇 가지 예제와 개념을 이해하고 특정 요구 사항에 따라 이후 예제로 이동하는 것입니다. 이 방법을 기반으로 간단한 "필수" 및 "선택적" 일대일 관계로 시작합니다.
팁
아래의 모든 예제에 대한 코드는 OneToOne.cs에서 찾을 수 있습니다.
필요한 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
일대일 관계는 다음으로 구성됩니다.
- 주 엔터티에 대한 하나 이상의 기본 또는 대체 키 속성. 예:
Blog.Id
. - 종속 엔터티의 하나 이상의 외래 키 속성. 예:
BlogHeader.BlogId
. - 필요에 따라 종속 엔터티를 참조하는 주 엔터티에 대한 참조 탐색. 예:
Blog.Header
. - 필요에 따라 주 엔터티를 참조하는 종속 엔터티에 대한 참조 탐색. 예:
BlogHeader.Blog
.
팁
일대일 관계의 어느 쪽이 보안 주체여야 하는지, 어느 쪽이 종속되어야 하는지 항상 명확하지는 않습니다. 몇 가지 고려 사항은 다음과 같습니다.
- 두 형식에 대한 데이터베이스 테이블이 이미 있는 경우 외래 키 열이 있는 테이블은 종속 형식에 매핑되어야 합니다.
- 형식은 일반적으로 다른 형식 없이 논리적으로 존재할 수 없는 경우 종속 형식입니다. 예를 들어 존재하지 않는 블로그의 헤더를 사용하는 것은 의미가 없으므로
BlogHeader
는 자연스럽게 종속 형식이 됩니다. - 자연스러운 부모/자식 관계가 있는 경우 자식은 일반적으로 종속 형식입니다.
따라서 이 예제의 관계에 대해 다음을 수행합니다.
- 외래 키 속성
BlogHeader.BlogId
는 null을 허용하지 않습니다. 이렇게 하면 외래 키 속성이 어떤 값으로 설정되어야 하므로 모든 종속(BlogHeader
)은 일부 보안 주체(Blog
)와 관련되어야 하기 때문에 관계가 "필수"가 됩니다. - 두 엔터티에는 관계의 반대편에 있는 관련 엔터티를 가리키는 탐색이 있습니다.
참고 항목
필수 관계는 모든 종속 엔터티를 일부 보안 주체 엔터티와 연결해야 합니다. 그러나 보안 주체 엔터티는 종속 엔터티 없이 항상 존재할 수 있습니다. 즉, 필수 관계는 항상 종속 엔터티가 있음을 나타내지 않습니다. EF 모델에는 방법이 없으며 관계형 데이터베이스에서도 보안 주체가 종속 항목과 연결되도록 하는 표준 방법이 없습니다. 필요한 경우 애플리케이션(비즈니스) 논리에서 구현해야 합니다. 자세한 내용은 필수 탐색을 참조하세요.
팁
두 탐색(종속 항목에서 보안 주체로의 관계와 보안 주체에서 종속 항목으로의 역)과의 관계를 양방향 관계라고 합니다.
이 관계는 규칙에 의해 검색됩니다. 구체적인 요건은 다음과 같습니다.
Blog
는 관계의 보안 주체로 검색되고BlogHeader
는 종속성으로 검색됩니다.BlogHeader.BlogId
는 보안 주체의Blog.Id
기본 키를 참조하는 종속 키의 외래 키로 검색됩니다.BlogHeader.BlogId
는 null을 허용하지 않으므로 관계가 필요에 따라 검색됩니다.Blog.BlogHeader
는 참조 탐색으로 검색됩니다.BlogHeader.Blog
는 참조 탐색으로 검색됩니다.
Important
C# null 허용 참조 형식을 사용하는 경우 외래 키 속성이 null 허용인 경우 보안 주체에 대한 종속에서 탐색은 null을 허용해야 합니다. 외래 키 속성이 null을 허용하지 않는 경우 탐색이 null을 허용하거나 그렇지 않을 수 있습니다. 이 경우 BlogHeader.BlogId
는 null을 허용하지 않으며 BlogHeader.Blog
도 null을 허용하지 않습니다. = null!;
구문은 EF가 일반적으로 Blog
인스턴스를 설정하고 완전히 로드된 관계에 대해 null일 수 없으므로 C# 컴파일러에 대한 의도적인 것으로 표시하는 데 사용됩니다. 자세한 내용은 null 허용 참조 형식 작업을 참조하세요.
규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
위의 예제에서 관계의 구성은 보안 주체 엔터티 형식(Blog
)을 시작합니다. 모든 관계와 마찬가지로 종속 엔터티 형식(BlogHeader
)으로 시작하는 것과 정확히 동일합니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne(e => e.Header)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
이러한 옵션 중 어느 것도 다른 옵션보다 낫지 않습니다. 둘 다 정확히 동일한 구성을 생성합니다.
팁
관계를 두 번 구성하고, 보안 주체에서 시작한 다음, 종속에서 다시 시작할 필요는 없습니다. 또한 관계의 보안 주체와 종속된 반쪽을 별도로 구성하려고 하면 일반적으로 작동하지 않습니다. 한쪽 끝 또는 다른 쪽에서 각 관계를 구성한 다음 구성 코드를 한 번만 작성하도록 선택합니다.
선택적 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int? BlogId { get; set; } // Optional foreign key property
public Blog? Blog { get; set; } // Optional reference navigation to principal
}
이는 보안 주체에 대한 외래 키 속성 및 탐색이 이제 null을 허용한다는 점을 제외하고 이전 예제와 동일합니다. 따라서 종속(BlogHeader
)은 외래 키 속성 및 탐색을 null
로 설정하여 어떠한 보안 주체(Blog
)와도 관련될 수 없으므로 관계를 "선택적"으로 만듭니다.
Important
C# null 허용 참조 형식을 사용하는 경우 외래 키 속성이 null 허용인 경우 보안 주체에 대한 종속에서 탐색 속성을 null 허용해야 합니다. 이 경우 BlogHeader.BlogId
는 null을 허용하므로 BlogHeader.Blog
도 null을 허용해야 합니다. 자세한 내용은 null 허용 참조 형식 작업을 참조하세요.
앞에서와 마찬가지로 이 관계는 규칙에 의해 검색됩니다. 규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired(false);
}
기본 키에서 기본 키로의 관계가 있는 필수 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
일대다 관계와 달리 일대일 관계의 종속 끝은 기본 키 속성 또는 속성을 외래 키 속성으로 사용할 수 있습니다. 이를 PK-PK 관계라고도 합니다. 종속 키의 기본 키가 null을 허용할 수 없으므로, 이는 보안 주체 및 종속 형식의 기본 키 형식이 같고 결과 관계가 항상 필요한 경우에만 가능합니다.
규칙에 의해 외래 키가 검색되지 않는 일대일 관계는 관계의 주체 및 종속 끝을 나타내도록 구성해야 합니다. 이 작업은 일반적으로 HasForeignKey
를 호출하여 수행됩니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>();
}
팁
이 목적을 위해 HasPrincipalKey
를 사용할 수도 있지만 그렇게 하는 것은 일반적이지 않습니다.
HasForeignKey
에 대한 호출에 속성이 지정되지 않고 기본 키가 적합한 경우 외래 키로 사용됩니다. 규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.Id)
.IsRequired();
}
섀도 외래 키가 있는 필수 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
외래 키는 데이터베이스에서 관계를 나타내는 방법에 대한 세부 정보이므로 순수하게 개체 지향적인 방식으로 관계를 사용할 때는 필요하지 않으므로 모델의 외래 키 속성을 원하지 않을 수 있습니다. 하지만 예를 들어 엔터티가 직렬화될 경우(예: 와이어를 통해 전송) 외래 키 값은 엔터티가 개체 형식에 없을 때 관계 정보를 그대로 유지하는 유용한 방법이 될 수 있습니다. 따라서 이러한 목적을 위해 .NET 형식에 외래 키 속성을 유지하는 것이 실용적입니다. 외래 키 속성은 프라이빗이 될 수 있으며, 이는 해당 값이 엔터티와 함께 이동하도록 허용하면서 외래 키가 노출되지 않도록 하는 좋은 타협입니다.
이전 예제에서 나아가, 다음 예제에서는 종속 엔터티 형식에서 외래 키 속성을 제거합니다. 그러나 기본 키를 사용하는 대신 EF는 int
형식의 BlogId
라는 섀도 외래 키 속성을 만들도록 지시됩니다.
여기서 유의해야 할 중요한 점은 C# null 참조 형식이 사용 중이므로 종속에서 보안 주체로의 탐색의 null 허용 여부를 사용하여 외래 키 속성이 null을 허용 가능한지 여부를 확인하므로 관계가 선택 사항인지 필수인지 여부를 결정합니다. null 허용 참조 형식을 사용하지 않는 경우 섀도 외래 키 속성은 기본적으로 관계를 선택적으로 설정하여 null을 허용합니다. 이 경우 IsRequired
를 사용하여 섀도 외래 키 속성을 null을 허용하지 않도록 강제하고 관계를 필수로 만듭니다.
이 관계에는 보안 주체 및 종속 끝을 나타내는 몇 가지 구성이 다시 필요합니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId");
}
규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
섀도 외래 키가 있는 선택적 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public Blog? Blog { get; set; } // Optional reference navigation to principal
}
이전 예제와 마찬가지로 외래 키 속성은 종속 엔터티 형식에서 제거되었습니다. 하지만 이전 예제와 달리 이번에는 C# null 허용 참조 형식이 사용되고 종속 엔터티 형식에 대한 탐색이 null을 허용하기 때문에 외래 키 속성이 null 허용으로 만들어집니다. 이렇게 하면 관계가 선택 사항으로 만들어집니다.
C# null 허용 참조 형식을 사용하지 않는 경우 외래 키 속성은 기본적으로 null 허용으로 만들어집니다. 즉, 자동으로 생성된 섀도 속성과의 관계는 기본적으로 선택 사항입니다.
이전과 마찬가지로 이 관계에는 보안 주체 및 종속 끝을 나타내는 몇 가지 구성이 필요합니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId");
}
규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired(false);
}
보안 주체에 대한 탐색이 없는 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
}
이 예제에서는 외래 키 속성이 다시 도입되었지만 종속에 대한 탐색이 제거되었습니다.
팁
하나의 탐색(보안 주체에 종속되거나 보안 주체에서 종속으로, 둘 다 아님)과의 관계를 단방향 관계라고 합니다.
외래 키가 검색되어 종속되는 쪽을 나타내므로 이 관계는 규칙에 의해 검색됩니다. 규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
WithOne
에 대한 호출에는 인수가 없습니다. 이는 BlogHeader
에서 Blog
로의 탐색이 없다는 것을 EF에 알리는 방법입니다.
탐색 없이 엔터티에서 구성을 시작하는 경우 제네릭 HasOne<>()
호출을 사용하여 관계의 다른 쪽 끝에 있는 엔터티의 형식을 명시적으로 지정해야 합니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne<Blog>()
.WithOne(e => e.Header)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
보안 주체에 대한 탐색이 없고 섀도 외래 키가 있는 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
}
이 예제에서는 외래 키 속성과 종속 항목의 탐색을 모두 제거하여 이전 예제 중 두 가지를 결합합니다.
이전과 마찬가지로 이 관계에는 보안 주체 및 종속 끝을 나타내는 몇 가지 구성이 필요합니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
필요에 따라 적절한 IsRequired()
또는 IsRequired(false)
를 호출하여 탐색 및 외래 키 이름을 명시적으로 구성하는 데 보다 완전한 구성을 사용할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne()
.HasForeignKey<BlogHeader>("BlogId")
.IsRequired();
}
보안 주체에 대한 탐색이 없는 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
이전 두 예제에는 보안 주체에서 종속 항목으로의 탐색이 있었지만 종속에서 보안 주체로의 탐색은 없었습니다. 다음 몇 가지 예제에서는 종속성의 탐색이 다시 도입되고 보안 주체에 대한 탐색은 대신 제거됩니다.
규칙에 따라 EF는 이를 일대다 관계로 처리합니다. 일대일로 만들려면 최소한의 구성이 필요합니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne();
}
이 방향으로 탐색이 없음을 나타내기 위해 WithOne()
이 인수 없이 호출됩니다.
규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogHeader>()
.HasOne(e => e.Blog)
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
탐색 없이 엔터티에서 구성을 시작하는 경우 제네릭 HasOne<>()
호출을 사용하여 관계의 다른 쪽 끝에 있는 엔터티의 형식을 명시적으로 지정해야 합니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne(e => e.Blog)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
탐색이 없는 일대일
경우에 따라 탐색 없이 관계를 구성하는 것이 유용할 수 있습니다. 이러한 관계는 외래 키 값을 직접 변경해야만 조작할 수 있습니다.
// Principal (parent)
public class Blog
{
public int Id { get; set; }
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
}
두 형식이 관련되어 있음을 나타내는 탐색이 없으므로 이 관계는 규칙에 의해 검색되지 않습니다. OnModelCreating
에서 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne();
}
이 구성에서는 BlogHeader.BlogId
속성이 규칙에 따라 외래 키로 검색되고 외래 키 속성이 null을 허용하지 않으므로 관계가 "필수"입니다. 외래 키 속성을 null 허용으로 만들어 관계를 "선택 사항"으로 만들 수 있습니다.
이 관계의 보다 완전한 명시적 구성은 다음과 같습니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne<BlogHeader>()
.WithOne()
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
대체 키가 있는 일대일
지금까지의 모든 예제에서 종속의 외래 키 속성은 보안 주체의 기본 키 속성으로 제한됩니다. 대신 외래 키를 다른 속성으로 제한한 다음 주 엔터티 형식의 대체 키가 될 수 있습니다. 예시:
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public int AlternateId { get; set; } // Alternate key as target of the BlogHeader.BlogId foreign key
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
EF는 항상 규칙에 따라 기본 키에 대한 관계를 만들기 때문에 이 관계는 규칙에 의해 검색되지 않습니다. HasPrincipalKey
에 대한 호출을 사용하여 OnModelCreating
에서 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => e.AlternateId);
}
HasPrincipalKey
는 다른 호출과 결합하여 탐색, 외래 키 속성 및 필수/선택적 특성을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => e.AlternateId)
.HasForeignKey<BlogHeader>(e => e.BlogId)
.IsRequired();
}
복합 외래 키가 있는 일대일
지금까지의 모든 예제에서 보안 주체의 기본 또는 대체 키 속성은 단일 속성으로 구성되었습니다. 기본 또는 대체 키는 둘 이상의 속성을 형성할 수도 있습니다. 이를 "복합 키"라고 합니다. 관계의 보안 주체에 복합 키가 있는 경우 종속의 외래 키도 동일한 수의 속성을 가진 복합 키여야 합니다. 예시:
// Principal (parent)
public class Blog
{
public int Id1 { get; set; } // Composite key part 1
public int Id2 { get; set; } // Composite key part 2
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId1 { get; set; } // Required foreign key property part 1
public int BlogId2 { get; set; } // Required foreign key property part 2
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
이 관계는 규칙에 의해 검색됩니다. 그러나 복합 키가 자동으로 검색되지 않으므로 복합 키가 명시적으로 구성된 경우에만 검색됩니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasKey(e => new { e.Id1, e.Id2 });
}
Important
복합 외래 키 값은 해당 속성 값이 null인 경우 null
인 것으로 간주됩니다. 하나의 속성이 null이고 다른 속성이 null이 아닌 복합 외래 키는 동일한 값을 가진 기본 또는 대체 키에 대한 일치 항목으로 간주되지 않습니다. 둘 다 null
로 간주됩니다.
HasForeignKey
및 HasPrincipalKey
모두 여러 속성이 있는 키를 명시적으로 지정하는 데 사용할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(
nestedBuilder =>
{
nestedBuilder.HasKey(e => new { e.Id1, e.Id2 });
nestedBuilder.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.HasPrincipalKey<Blog>(e => new { e.Id1, e.Id2 })
.HasForeignKey<BlogHeader>(e => new { e.BlogId1, e.BlogId2 })
.IsRequired();
});
}
팁
위의 코드에서 HasKey
및 HasOne
에 대한 호출은 중첩된 작성기에 함께 그룹화되었습니다. 중첩된 작성기에서는 동일한 엔터티 형식에 대해 Entity<>()
를 여러 번 호출할 필요가 없지만 기능적으로는 Entity<>()
를 여러 번 호출하는 것과 동일합니다.
계단식 삭제가 없는 필수 일대일
// Principal (parent)
public class Blog
{
public int Id { get; set; }
public BlogHeader? Header { get; set; } // Reference navigation to dependent
}
// Dependent (child)
public class BlogHeader
{
public int Id { get; set; }
public int BlogId { get; set; } // Required foreign key property
public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}
규칙에 따라 필수 관계는 계단식 삭제로 구성됩니다. 보안 주체가 삭제된 후에는 데이터베이스에 종속이 존재할 수 없기 때문입니다. 데이터베이스는 더 이상 존재하지 않는 종속 행을 자동으로 삭제하는 대신 일반적으로 애플리케이션이 충돌하는 오류를 생성하도록 구성할 수 있습니다. 이렇게 하려면 몇 가지 구성이 필요합니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(e => e.Header)
.WithOne(e => e.Blog)
.OnDelete(DeleteBehavior.Restrict);
}
일대일 자체 참조
이전의 모든 예제에서 주 엔터티 형식은 종속 엔터티 형식과 달랐습니다. 꼭 그럴 필요는 없습니다. 예를 들어 아래 형식에서 각 Person
은 필요에 따라 다른 Person
과 관련됩니다.
public class Person
{
public int Id { get; set; }
public int? HusbandId { get; set; } // Optional foreign key property
public Person? Husband { get; set; } // Optional reference navigation to principal
public Person? Wife { get; set; } // Reference navigation to dependent
}
이 관계는 규칙에 의해 검색됩니다. 규칙에 따라 관계의 탐색, 외래 키 또는 필수/선택적 특성이 검색되지 않는 경우 이러한 항목을 명시적으로 구성할 수 있습니다. 예시:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOne(e => e.Husband)
.WithOne(e => e.Wife)
.HasForeignKey<Person>(e => e.HusbandId)
.IsRequired(false);
}
참고 항목
일대일 자체 참조 관계의 경우 보안 주체 및 종속 엔터티 형식이 동일하기 때문에 외래 키가 포함된 형식을 지정해도 종속 끝은 명확히 표시되지 않습니다. 이 경우 종속에서 보안 주체로의 HasOne
지점에 지정된 탐색과 보안 주체에서 종속으로의 WithOne
지점에 지정된 탐색이 있습니다.
.NET