다음 엔티티가 있다고 가정 해 보겠습니다.
public class Parent
{
public int Id { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
}
탐색 속성을 가질 필요없이 Parents 테이블에 대한 외래 키 제약 조건을 사용하여 ParentId가 데이터베이스에 생성되도록하는 코드 첫 번째 유창한 API 구문은 무엇입니까 ?
탐색 속성 Parent를 Child에 추가하면 다음과 같이 할 수 있습니다.
modelBuilder.Entity<Child>()
.HasRequired<Parent>(c => c.Parent)
.WithMany()
.HasForeignKey(c => c.ParentId);
하지만이 특별한 경우에는 탐색 속성을 원하지 않습니다.
답변
EF Code First Fluent API로는 불가능합니다. 데이터베이스에서 외래 키 제약 조건을 만들려면 항상 하나 이상의 탐색 속성이 필요합니다.
Code First 마이그레이션을 사용하는 경우 패키지 관리자 콘솔 ( add-migration SomeNewSchemaName
) 에서 새 코드 기반 마이그레이션을 추가하는 옵션이 있습니다 . 모델 또는 매핑으로 변경 한 경우 새 마이그레이션이 추가됩니다. 아무것도 변경하지 않은 경우 add-migration -IgnoreChanges SomeNewSchemaName
. 이 경우 마이그레이션에는 비어있는 Up
및 Down
메소드 만 포함됩니다 .
그런 Up
다음 다음을 추가하여 메서드를 수정할 수 있습니다 .
public override void Up()
{
// other stuff...
AddForeignKey("ChildTableName", "ParentId", "ParentTableName", "Id",
cascadeDelete: true); // or false
CreateIndex("ChildTableName", "ParentId"); // if you want an index
}
이 마이그레이션을 실행하면 ( update-database
패키지 관리 콘솔에서) 다음과 유사한 SQL 문이 실행됩니다 (SQL Server의 경우).
ALTER TABLE [ChildTableName] ADD CONSTRAINT [FK_SomeName]
FOREIGN KEY ([ParentId]) REFERENCES [ParentTableName] ([Id])
CREATE INDEX [IX_SomeName] ON [ChildTableName] ([ParentId])
또는 마이그레이션없이 다음을 사용하여 순수 SQL 명령을 실행할 수 있습니다.
context.Database.ExecuteSqlCommand(sql);
여기서는 context
파생 된 컨텍스트 클래스의 인스턴스이며 sql
위의 SQL 명령 (문자열)입니다.
이 모든 EF에는 ParentId
관계를 설명하는 외래 키라는 단서가 없습니다 . EF는이를 일반 스칼라 속성으로 만 간주합니다. 어떻게 든 위의 모든 것은 SQL 관리 도구를 열고 수동으로 제약 조건을 추가하는 것에 비해 더 복잡하고 느린 방법입니다.
답변
이 게시물에 대한하지만 Entity Framework
하지 Entity Framework Core
, 그것은 (나는 V1.1.2을 사용하고 있습니다) 엔티티 프레임 워크 코어를 사용하여 같은 일을 달성하기 위해 원하는 사람을 위해 유용 할 수 있습니다.
나는 (비록 그들이있는 거 좋은) 탐색 속성을하지 않아도 내가 DDD를 연습하고 내가 원하기 때문에 Parent
그리고 Child
두 개의 별도의 집계 뿌리가 될 수 있습니다. 인프라 별 Entity Framework
탐색 속성이 아닌 외래 키를 통해 서로 대화 할 수 있기를 바랍니다 .
당신이해야 할 모든 이용하여 한쪽의 관계를 구성하는 것입니다 HasOne
하고 WithMany
(그들은 결국이 아니에요) 탐색 속성을 지정하지 않고.
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}
protected override void OnModelCreating(ModelBuilder builder)
{
......
builder.Entity<Parent>(b => {
b.HasKey(p => p.Id);
b.ToTable("Parent");
});
builder.Entity<Child>(b => {
b.HasKey(c => c.Id);
b.Property(c => c.ParentId).IsRequired();
// Without referencing navigation properties (they're not there anyway)
b.HasOne<Parent>() // <---
.WithMany() // <---
.HasForeignKey(c => c.ParentId);
// Just for comparison, with navigation properties defined,
// (let's say you call it Parent in the Child class and Children
// collection in Parent class), you might have to configure them
// like:
// b.HasOne(c => c.Parent)
// .WithMany(p => p.Children)
// .HasForeignKey(c => c.ParentId);
b.ToTable("Child");
});
......
}
}
엔티티 속성을 구성하는 방법에 대한 예제도 제공하지만 여기서 가장 중요한 것은 HasOne<>
, WithMany()
및 HasForeignKey()
입니다.
도움이 되었기를 바랍니다.
답변
DataAnotations를 사용하고 탐색 속성을 노출하고 싶지 않은 사람들을위한 작은 힌트-사용 protected
public class Parent
{
public int Id { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
protected virtual Parent Parent { get; set; }
}
그것은 그게 전부 -와 외래 키 cascade:true
후가 Add-Migration
생성됩니다.
답변
EF Core의 경우 탐색 속성을 제공 할 필요가 없습니다. 관계의 한쪽에 간단히 외래 키를 제공 할 수 있습니다. Fluent API를 사용한 간단한 예 :
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
namespace EFModeling.Configuring.FluentAPI.Samples.Relationships.NoNavigation
{
class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne<Blog>()
.WithMany()
.HasForeignKey(p => p.BlogId);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
}
}
답변
.Net Core 3.1, EntityFramework 3.1.3을 사용하고 있습니다. 나는 주변을 찾고 있었고 내가 생각해 낸 해결책은 HasForeginKey<DependantEntityType>(e => e.ForeginKeyProperty)
. 다음과 같이 일대일 관계를 만들 수 있습니다.
builder.entity<Parent>()
.HasOne<Child>()
.WithOne<>()
.HasForeginKey<Child>(c => c.ParentId);
builder.entity<Child>()
.Property(c => c.ParentId).IsRequired();
이것이 도움이되거나 적어도 방법을 사용하는 HasForeginKey
방법 에 대한 다른 아이디어를 제공하기를 바랍니다 .
답변
탐색 속성을 사용 하지 않는 이유 는 클래스 종속성입니다. 내 모델을 몇 개의 어셈블리로 분리하여 다른 프로젝트에서 어떤 조합으로도 사용하거나 사용할 수 없습니다. 따라서 다른 어셈블리의 클래스에 대한 nagivation 속성이있는 엔터티가있는 경우 해당 어셈블리를 참조해야합니다.이 어셈블리는 피하고 싶습니다 (또는 전체 데이터 모델의 일부를 사용하는 모든 프로젝트는 모든 것을 포함합니다).
그리고 마이그레이션 (자동 마이그레이션 사용)과 초기 DB 생성에 사용되는 별도의 마이그레이션 앱이 있습니다. 이 프로젝트는 명백한 이유로 모든 것을 참조합니다.
해결책은 C 스타일입니다.
- 링크를 통해 마이그레이션 프로젝트에 대상 클래스가있는 “복사”파일 (
alt
VS의 키로 끌어서 놓기 ) - nagivation 속성 (및 FK 속성) 비활성화
#if _MIGRATION
- 마이그레이션 앱에서 해당 전 처리기 정의를 설정하고 모델 프로젝트에서 설정하지 않으므로 아무것도 참조하지 않습니다 (
Contact
예제에서 클래스로 어셈블리를 참조하지 않음 ).
견본:
public int? ContactId { get; set; }
#if _MIGRATION
[ForeignKey(nameof(ContactId))]
public Contact Contact { get; set; }
#endif
물론 동일한 방법으로 using
지시문을 비활성화 하고 네임 스페이스를 변경해야합니다.
그 후 모든 소비자는 해당 속성을 일반적인 DB 필드로 사용할 수 있지만 (필요하지 않은 경우 추가 어셈블리를 참조하지 않음) DB 서버는 이것이 FK이고 캐스 케이 딩을 사용할 수 있음을 알게됩니다. 매우 더러운 솔루션. 하지만 작동합니다.