EF Core多对多不需要的列

时间:2019-03-18 17:21:57

标签: c# .net-core entity-framework-core ef-migrations

我正在尝试创建一个具有两次多对多关系的模型。

  

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类内创建其他不必要的字段。迁移希望将可为空的StockItemIdArticleId都添加到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 :(得分:0)

StockItemArticle的配置映射在哪里?而且我认为您在.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)的属性。

嗯?他们不一样吗?这就是为什么我认为实体框架感到困惑。并且由于您没有具有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