EF Core много-много нежелательных столбцов - PullRequest
0 голосов
/ 18 марта 2019

Я пытаюсь создать модель, которая имеет отношение два ко многим.

StockItem * - * QualityCheckDefinition

Статья * - * QualityCheckDefinition

Многие ко многим классам:

public class StockItemQualityCheckDefinition
{
    public StockItem StockItem { get; set; }
    public QualityCheckDefinition QualityCheckDefinition { get; set; }

    public int StockItemId { get; set; }
    public int QualityCheckDefinitionId { get; set; }
}

public class ArticleQualityCheckDefinition
{
    public Article Article { get; set; }
    public QualityCheckDefinition QualityCheckDefinition { get; set; }

    public string ArticleId { get; set; }
    public int QualityCheckDefinitionId { get; set; }
}

Класс QualityCheckDefinition:

public class QualityCheckDefinition : Entity<int>
{
    public List<StockItemQualityCheckDefinition> StockItemQualityCheckDefinitions { get; set; }
    public List<ArticleQualityCheckDefinition> ArticleQualityCheckDefinitions { get; set; }         
}

Класс товара:

public class Article : Entity<string>
{
    public ICollection<ArticleQualityCheckDefinition> ArticleQualityCheckDefinitions { get; set; }
}

StockItem класс:

public class StockItem : Entity<int>
{
    public List<StockItemQualityCheckDefinition> StockItemQualityCheckDefinitions { get; set; }
}

Отображения:

public class ArticleQualityCheckDefinitionMap : IEntityTypeConfiguration<ArticleQualityCheckDefinition>
{
    public void Configure(EntityTypeBuilder<ArticleQualityCheckDefinition> builder)
    {
        builder.HasKey(x => new { x.ArticleId, x.QualityCheckDefinitionId });

        builder.HasOne(x => x.Article)
               .WithMany(x => x.ArticleQualityCheckDefinitions)
               .HasForeignKey(x => x.ArticleId)
               .HasPrincipalKey(x => x.Id)
               .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne(x => x.QualityCheckDefinition)
               .WithMany(x => x.ArticleQualityCheckDefinitions)
               .HasForeignKey(x => x.QualityCheckDefinitionId)
               .HasPrincipalKey(x => x.Id)
               .OnDelete(DeleteBehavior.Restrict);
    }
}

public class StockItemQualityDefinitionMap : IEntityTypeConfiguration<StockItemQualityCheckDefinition>
{
    public void Configure(EntityTypeBuilder<StockItemQualityCheckDefinition> builder)
    {
        builder.HasKey(x => new { x.StockItemId, x.QualityCheckDefinitionId });

        builder.HasOne(x => x.StockItem)
               .WithMany(x => x.StockItemQualityCheckDefinitions)
               .HasForeignKey(x => x.StockItemId);

        builder.HasOne(x => x.QualityCheckDefinition)
               .WithMany(x => x.StockItemQualityCheckDefinitions)
               .HasForeignKey(x => x.QualityCheckDefinitionId);
    }
}

Отношения настроены нормально, и они работают. Однако миграция создает дополнительные ненужные поля внутри класса QualityCheckDefinition. Миграция хочет добавить и обнуляемые StockItemId и ArticleId в класс QualityCheckDefinition.

Существует часть миграции:

migrationBuilder.CreateTable(
                name: "QualityCheckDefinitions",
                columns: table => new
                {
                    Id = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    //other properties
                    ArticleId = table.Column<string>(nullable: true),
                    StockItemId = table.Column<int>(nullable: true)
                },

Почему он добавляет эти нежелательные ключи?

PS. Я использую EF Core 2.2

1 Ответ

0 голосов
/ 19 марта 2019

Где ваше отображение конфигурации для StockItem и Article? И я думаю, что вы использовали .HasPrincipalKey() внутри ArticleQualityCheckDefinitionMap не правильно.

Основной ключ

Если вы хотите, чтобы внешний ключ ссылался на свойство, отличное от первичного ключа, вы можете использовать Fluent API для настройки свойства основного ключа для отношения. Свойство, которое вы настраиваете в качестве основного ключа, будет автоматически настроено как альтернативный ключ.

Ваш ArticleQualityCheckDefinitionMap

builder.HasOne(x => x.Article)
    .WithMany(x => x.ArticleQualityCheckDefinitions)
    .HasForeignKey(x => x.ArticleId)        // <--
    .HasPrincipalKey(x => x.Id)             // <--
    .OnDelete(DeleteBehavior.Restrict);

По соглашениям .HasForeignKey(x => x.ArticleId) будет нацелен на первичный ключ объекта Article, string Id. И тогда вы сказали Entity Framework, что не хотите устанавливать внешний ключ для первичного ключа. Вы хотите настроить таргетинг на другое свойство с именем Id, сказав .HasPrincipalKey(x => x.Id).

А? Разве они не одинаковы? Вот почему я думаю, что Entity Framework запутался. И поскольку у вас нет конфигурации для Article, Entity Framework старалась изо всех сил сгенерировать для вас первичный ключ с именем "ArticleId"?

Вы можете устранить проблему, просто добавив конфигурации обратно и удалив .HasPrincipalKey() там.

StockItemConfiguration

using DL.SO.EFCore.Learning.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DL.SO.EFCore.Learning.Data.Configurations
{
    public class StockItemConfiguration : IEntityTypeConfiguration<StockItem>
    {
        public void Configure(EntityTypeBuilder<StockItem> builder)
        {
            builder.HasKey(x => x.Id);

            builder.ToTable(nameof(StockItem));
        }
    }
}

ArticleConfiguration

using DL.SO.EFCore.Learning.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DL.SO.EFCore.Learning.Data.Configurations
{
    public class ArticleConfiguration : IEntityTypeConfiguration<Article>
    {
        public void Configure(EntityTypeBuilder<Article> builder)
        {
            builder.HasKey(x => x.Id);

            builder.ToTable(nameof(Article));
        }
    }
}

Возможно, вам также потребуется настроить для QualityCheckDefinition:

QualityCheckDefinitionConfiguration

using DL.SO.EFCore.Learning.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DL.SO.EFCore.Learning.Data.Configurations
{
    public class QualityCheckDefinitionConfiguration : IEntityTypeConfiguration<QualityCheckDefinition>
    {
        public void Configure(EntityTypeBuilder<QualityCheckDefinition> builder)
        {
            builder.HasKey(x => x.Id);

            builder.ToTable(nameof(QualityCheckDefinition));
        }
    }
}

Затем удалите .HasPrincipalKey():

ArticleQualityCheckDefinitionConfiguration

using DL.SO.EFCore.Learning.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DL.SO.EFCore.Learning.Data.Configurations
{
    public class ArticleQualityCheckDefinitionConfiguration : IEntityTypeConfiguration<ArticleQualityCheckDefinition>
    {
        public void Configure(EntityTypeBuilder<ArticleQualityCheckDefinition> builder)
        {
            builder.HasKey(x => new { x.ArticleId, x.QualityCheckDefinitionId });

            builder.HasOne(x => x.Article)
                .WithMany(x => x.ArticleQualityCheckDefinitions)
                .HasForeignKey(x => x.ArticleId);

            builder.HasOne(x => x.QualityCheckDefinition)
                .WithMany(x => x.ArticleQualityCheckDefinitions)
                .HasForeignKey(x => x.QualityCheckDefinitionId);

            builder.ToTable(nameof(ArticleQualityCheckDefinition));
        }
    }
}

Тогда с тобой все будет в порядке?

enter image description here

...