솔리드 프레임워크 코어 5.0의 다중 지원 시도

실체 프레임워크 6에서 제공하는 기능은 실체 프레임워크 핵심에 부족합니다. 즉, 다중 지원이지만 최종적으로 5.0에서 완성될 것 같습니다.
이것은 우리가 줄곧 EF코어에서 실현하고자 하는 기능이기도 하다. 왜냐하면 그것은 사용하기 편리하기 때문에 중간 시계를 걱정할 필요가 없다.
트위터에서 말한 바와 같이 일상적인 구축에서 사용할 수 있으나preview8에도 기본 지원이 포함되어 있습니다.1

아서 빅스
@ajcvickers 회사

매주 하이라이트 업데이트» Blazor 어플리케이션의 EF Core에 대한 주요 새 가이드 및 샘플!다대다 일상 구축에서 완성!커뮤니티는 유튜브에 서서 45분 동안 다중 프레젠테이션을 합니다!github.com/dotnet/efcore/…
18:00 PM-2020년 8월 20일
유튜브의 커뮤니티 스테이션에서도 시연을 해서 보기 좋다.물론 문서가 존재하지 않기 때문에 유일하게 사용할 수 있는 공식 정보가 될 것이라고 생각합니다.
이 세계에서 Dapper 같은 마이크로orm은 실체 프레임워크 핵심과 같은 전 기능 orm보다 우수하고 KVS는 구름에서 처리하는 확장성 면에서 RDB보다 우월하다.
나는 그것들을 정확하게 사용하는 것이 좋은 생각이라고 생각한다.
사실 실체 프레임워크의 핵심도 상당히 선진적이다. 만약 당신이 이미 2.0/2.1로 그것을 접촉하고 포기했다면 그것을 쫓는 것은 좋은 생각이다.

예비적


이것은 약간 주제에서 벗어났지만, 우리는 다중 지원의 실제 테스트를 위해 준비를 해야 한다.구체적으로 말하자면, 우리는 EF Core의 일상적인 구축을 설정하고, 그것을 설치하기 위해 기본 코드를 추가하기만 하면 된다.
이 모든 코드는 5.0.0-rc.1.20431.2 로 검사를 진행했다.버전 6.0은 이미 일상적으로 구축 중이므로 조심해야 합니다.
https://github.com/dotnet/aspnetcore/blob/master/docs/DailyBuilds.md
기본 코드는 다음과 같습니다.LocalDB를 사용하지만 설치하지 않으려면 SQLite에 Provider를 설치할 수 있습니다.
설정에서 DI를 사용하지 않고 콘솔 응용 프로그램을 사용하여 빠르게 실행할 경우를 가정합니다.
public class AppDbContext : DbContext
{
    public DbSet<Entry> Entries { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=ManyToManySample;Trusted_Connection=True;MultipleActiveResultSets=true");
    }
}

public class Entry
{
    public int Id { get; set; }
    public string Title { get; set; }
    public List<Tag> Tags { get; } = new List<Tag>();
}

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Entry> Entries { get; } = new List<Entry>();
}
이 모형은 설명할 필요가 없다.이것은 우리가 과거에 자주 사용했던 항목에 여러 개의 표시를 추가할 수 있도록 합니다.이것은 다대다 모형을 형성했다.

정의되지 않은 중간표 사용하기


첫 번째는 EF6에서 자주 사용하는 모드입니다. 이 모드는 중간 테이블을 명시적으로 정의하지 않지만 모든 내용을 실체 프레임의 핵심에 남겨 둡니다.
이 모드의 장점은 필요한 중간 테이블이 EF 핵심에 의해 자동으로 생성되어 RDB단을 고려하지 않고 사용할 수 있다는 것이다.
EF 코어 끝에서 정의는 다음과 같이 간단합니다.겸사겸사 한마디 하자면, 그 중 하나만 정의하면 됩니다.
public class AppDbContext : DbContext
{
    public DbSet<Entry> Entries { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=ManyToManySample;Trusted_Connection=True;MultipleActiveResultSets=true");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Entry>()
                    .HasMany(x => x.Tags)
                    .WithMany(x => x.Entries);
    }
}
만약 우리가 Add-Migration 로 이전 코드를 만들고 이 상태에서 실행한다면 Update-Database 다음 세 개의 표를 만들 것입니다.

현재 우리는 실제적으로 항목을 추가할 수 있도록 설정과 표를 준비했다.이 영역은 EF 6와 거의 동일하므로 문제 없이 사용할 수 있어야 합니다.
class Program
{
    static async Task Main(string[] args)
    {
        using var context = new AppDbContext();

        var entry = new Entry
        {
            Title = "buchizo"
        };

        entry.Tags.AddRange(new[]
        {
            new Tag { Name = "kosmosebi" },
            new Tag { Name = "rd" }
        });

        await context.AddAsync(entry);
        await context.SaveChangesAsync();
    }
}
그것을 실행할 때, 데이터가 중간 테이블에 정확하게 추가된 것을 볼 수 있습니다.

마지막으로 우리는 조회를 하나 던져 봅시다.Include 현식 지정을 사용하지 마운트하지 마십시오. 그렇지 않으면 빈 집합을 얻을 수 있습니다.
EF 6에서 기본적으로 지연 로딩이 사용되기 때문에 이것은 내가 진정으로 관심을 가지지 않는 부분이라고 생각한다.
class Program
{
    static async Task Main(string[] args)
    {
        using var context = new AppDbContext();

        var entry = await context.Entries
                                 .Include(x => x.Tags)
                                 .FirstAsync(x => x.Id == 1);
    }
}
그것을 실행할 때 Tags 데이터도 포함됩니다.이것은 매우 쉽다.

나는 이것이 기본 모델이 될 것이라고 생각하지만 실체 프레임워크의 핵심은 더욱 많은 확장성을 허용하기 때문에 나도 이에 대해 신속하게 정리할 것이다.

중간 테이블의 이름을 지정합니다.


EF Core가 중간 테이블을 처리하도록 하면 이름을 지정할 수 없지만 테이블 이름을 지정할 때 호출할 수 있습니다 UsingEntity<T>.
이 규범은 작성하기가 좀 까다롭다.
중간 테이블에 모델을 준비할 수 있지만 EF CoreDictionary<TKey, TValue>는 각 섹션에서 사용할 수 있으므로 모델을 정의하지 않고 호출할 수 있습니다.
public class AppDbContext : DbContext
{
    public DbSet<Entry> Entries { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=ManyToManySample;Trusted_Connection=True;MultipleActiveResultSets=true")
                      .UseLazyLoadingProxies();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Entry>()
                    .HasMany(x => x.Tags)
                    .WithMany(x => x.Entries)
                    .UsingEntity<Dictionary<string, object>>(
                        "EntryTagMaps",
                        x => x.HasOne<Tag>().WithMany(),
                        x => x.HasOne<Entry>().WithMany());
    }
}
그것을 작성하는 것은 상당히 불편한 방식이지만, 우리는 모델을 정의하지 않은 상황에서 표 이름을 지정할 수 있다.

EF Core는 속성을 정의하지 않고도 Indexer를 사용하여 모델을 준비할 수 있기 때문에 EF 6와 크게 다릅니다.비록 유연하지만, 이것은 당신이 대량으로 사용하고 싶지 않은 기능입니다. 왜냐하면 패턴을 혼동하기 때문입니다.

중간 테이블을 명시적으로 정의하여 사용합니다.


마지막 모델은 중간 테이블을 정의하고 사용하는 모델이다.
EF Core 5.0 이전에 다중 대 다중을 구현하려면 중간 테이블을 정의하고 다음 문서를 통해 처리하는 방법에 대해 주로 썼습니다.
https://docs.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#many-to-many
EF Core 5.0으로 변경하려면 기존 중간 테이블 모드가 자동 생성 모드와 다를 수 있으므로 UsingEntity<T> 를 사용하여 개별적으로 정의할 수 있습니다.
다음 코드는 EntryTagMap 클래스의 모든 속성을 연결합니다.
public class EntryTagMap
{
    public int EntryId { get; set; }
    public Entry Entry { get; set; }

    public int TagId { get; set; }
    public Tag Tag { get; set; }
}

public class AppDbContext : DbContext
{
    public DbSet<Entry> Entries { get; set; }
    public DbSet<Tag> Tags { get; set; }
    public DbSet<EntryTagMap> EntryTagMaps { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=ManyToManySample;Trusted_Connection=True;MultipleActiveResultSets=true");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Entry>()
                    .HasMany(x => x.Tags)
                    .WithMany(x => x.Entries)
                    .UsingEntity<EntryTagMap>(
                        x => x.HasOne(xs => xs.Tag).WithMany(),
                        x => x.HasOne(xs => xs.Entry).WithMany())
                    .HasKey(x => new { x.EntryId, x.TagId });
    }
}
만약 외부 키가 약정과 다르다면, HasForeignKey 다음에 WithMany 를 추가하여 명확하게 지정하십시오.
현재, 당신은 기존의 중간표 모드와 일치하는 방식으로 여러 쌍을 설정할 수 있습니다.

지연 로드와 함께 사용


나는 그것을 지연 적재와 함께 보상으로 사용할 것이다.
N+1 문제가 발생하기 쉽기 때문에 적절히 사용하십시오.지정할 필요가 없습니다Include.
이전 버전에 비해 사용 방법은 변경되지 않았으므로 아래 문서와 항목을 참조하여 설정을 추가하십시오.물론 가방은 매일 구축 버전에 적응해야 한다.
https://docs.microsoft.com/en-us/ef/core/querying/related-data#lazy-loading
가장 간단한 정의에서 지연 불러오기를 사용합시다.
이렇게 하면 UseLazyLoadingProxies에 대한 호출을 추가하고 내비게이션 속성을 virtual 수식자로 변경할 수 있습니다.
부족한 설정은 실행 Add-Migration 시 오류 메시지를 통해 통지되기 때문에 유용합니다.
public class AppDbContext : DbContext
{
    public DbSet<Entry> Entries { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=ManyToManySample;Trusted_Connection=True;MultipleActiveResultSets=true")
                      .UseLazyLoadingProxies();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Entry>()
                    .HasMany(x => x.Tags)
                    .WithMany(x => x.Entries);
    }
}

public class Entry
{
    public int Id { get; set; }
    public string Title { get; set; }
    public virtual List<Tag> Tags { get; set; } = new List<Tag>();
}

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual List<Entry> Entries { get; set; } = new List<Entry>();
}
지연 불러오기를 사용했기 때문에 검색에서 Include 호출을 삭제할 수 있습니다.
class Program
{
    static async Task Main(string[] args)
    {
        using var context = new AppDbContext();

        var entry = await context.Entries
                                 .FirstAsync(x => x.Id == 1);

        var tags = entry.Tags;
    }
}
이를 실행하면 Tags 로드 지연이 표시됩니다.로그를 출력하면 이해하기 쉬울 것이다.

이것은 매우 저조하지만, 실제 코드에 이 영역을 사용할지 여부를 결정할 수 있습니다.
그러면 EF 6에서 EF Core로의 전환이 더욱 원활해집니다.
그러나 아직 실현되지 않은 부분이 많다는 것을 주의하십시오. 

좋은 웹페이지 즐겨찾기