【问题标题】:EF Core 5 Migration Creating Table Twice With Different NameEF Core 5 迁移使用不同名称两次创建表
【发布时间】:2022-01-27 13:59:49
【问题描述】:

我正在使用 Visual Studio Community 2022(64 位,版本 17.1.0 预览版 1.1)、ASP .Net 5 Razor Pages(非 MVC)、EF Core 5 和 SQL Server。

我有两个类,它们具有多对多关系。

1 类(标签):

public class Tag
{
    [Key]
    public int Id { get; set; }

    [Required]
    [Display(Name = "Tag Description")]
    [StringLength(50, ErrorMessage = "Description cannot be longer than 50 characters.")]
    public string Description { get; set; }

    [Required]
    public string Narrative { get; set; }

    //Tags Have One Subject
    //Tag.SubjectId FK
    [ForeignKey("SubjectID")]
    public int SubjectId { get; set; }
    public Subject Subject { get; set; }

    //Tags Have One Or More Documents
    //(TagDocument Join Table)
    public List<TagDocument> TagDocuments { get; set; }

    //Tags Have One Or More Acronyms
    //TagAcronym Join Table
    public ICollection<Acronym> Acronyms { get; set; }
    public List<TagAcronym> TagAcronyms { get; set; }
}

第 2 类(首字母缩写词):

 public class Acronym
 {
     [Key]
     public int Id { get; set; }

     [Required]
     [Display(Name = "Acronym")]
     [StringLength(50, ErrorMessage = "Acronym cannot be longer than 50 characters.")]
     public string Abbreviation { get; set; }

     [Required]
     [Display(Name = "Description")]
     [StringLength(100, ErrorMessage = "Description cannot be longer than 100 characters.")]
     public string Description { get; set; }

     [StringLength(250, ErrorMessage = "URL cannot be longer than 250 characters.")]
     public string URL { get; set; }

     //Acronyms Have One Or More AcronymOld
     //AcronymOld.AcronymId (FK)
     public List<AcronymOld> AcronymsOld { get; set; }

     //Acronyms Have One Or More Tags
     //TagAcronym Join Table
     public ICollection<Tag> Tags { get; set; }
     public List<TagAcronym> TagAcronyms { get; set; }
 }

任何首字母缩写词都可以有很多标签,一个标签可以有很多首字母缩写词。

我创建了一个 TagAcronym 类以方便在数据库中创建 Join Table:

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

        public int AcronymId { get; set; }
        public Acronym Acronym { get; set; }
    }
}

当我创建迁移时,它尝试创建一个 TagAcronym 和一个 AcronymTag 表,原因我无法理解。

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "AcronymTag",
        columns: table => new
        {
            AcronymsId = table.Column<int>(type: "int", nullable: false),
            TagsId = table.Column<int>(type: "int", nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_AcronymTag", x => new { x.AcronymsId, x.TagsId });
            table.ForeignKey(
                name: "FK_AcronymTag_Acronym_AcronymsId",
                column: x => x.AcronymsId,
                principalTable: "Acronym",
                principalColumn: "Id",
                onDelete: ReferentialAction.Cascade);
            table.ForeignKey(
                name: "FK_AcronymTag_Tag_TagsId",
                column: x => x.TagsId,
                principalTable: "Tag",
                principalColumn: "Id",
                onDelete: ReferentialAction.Cascade);
        });

    migrationBuilder.CreateTable(
        name: "TagAcronym",
        columns: table => new
        {
            TagId = table.Column<int>(type: "int", nullable: false),
            AcronymId = table.Column<int>(type: "int", nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_TagAcronym", x => new { x.TagId, x.AcronymId });
            table.ForeignKey(
                name: "FK_TagAcronym_Acronym_AcronymId",
                column: x => x.AcronymId,
                principalTable: "Acronym",
                principalColumn: "Id",
                onDelete: ReferentialAction.Cascade);
            table.ForeignKey(
                name: "FK_TagAcronym_Tag_TagId",
                column: x => x.TagId,
                principalTable: "Tag",
                principalColumn: "Id",
                onDelete: ReferentialAction.Cascade);
        });

    migrationBuilder.CreateIndex(
        name: "IX_AcronymTag_TagsId",
        table: "AcronymTag",
        column: "TagsId");

    migrationBuilder.CreateIndex(
        name: "IX_TagAcronym_AcronymId",
        table: "TagAcronym",
        column: "AcronymId");
}

感谢任何帮助。谢谢。

【问题讨论】:

  • 我首先要看的是你似乎在你的实体之间建立了两次关系。一个标签有一个ICollection&lt;Acronym&gt; 属性(首字母缩略词有一个ICollection&lt;Tag&gt;),EF 会理解它是一个直接的多:多,它会让中间人表让你将它分成两个多:1 rels.. 但是你然后也让每个 ent 都有一个 List&lt;TagAcronym&gt; 以便让 EF 通过制作自己的中间人来帮助您,您还可以手动制作自己的中间人实体。决定你想要的工作方式(隐藏的或可见的中间人)并移除另一个,看看会发生什么......
  • (我个人会删除 ICollection&lt;Tag/Acronym&gt; 道具,将 List&lt;TagAcronym&gt; 翻转为 ICollection 并将其初始化为哈希集而不是列表,并与可见的中间人一起工作: someTag.TagAcronym.Acronyms.Where(...) vs someTag.Acronyms.Where(...) 因为我发现迟早,可能更早,老板想要一些东西,这意味着我需要在 TagAcronym 表中存储更多数据..)
  • 您能否包括在您的上下文中如何配置实体?您的实体设置与官方docs 接近,但有些偏差。
  • 是的,@CaiusJard 你的解释非常详细和正确。
  • 如何配置多对多连接?还是一切都是按照惯例推断出来的?恕我直言,改为明确定义关系 (docs.microsoft.com/en-us/ef/core/modeling/…)。

标签: c# asp.net-core entity-framework-core razor-pages


【解决方案1】:

Tag 和 Acronym 之间的关系是多对多的,因此 EF 会自动为这些带有名称(TagAcronym 或 AcronymTag)的表创建映射表,因此您无需显式指定 TagAcroymn 表。

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案2】:

你可以使用这个模型设计:

public class Tag
    {
        [Key]
        public int Id { get; set; }

        [Required]
        [Display(Name = "Tag Description")]
        [StringLength(50, ErrorMessage = "Description cannot be longer than 50 characters.")]
        public string Description { get; set; }

        [Required]
        public string Narrative { get; set; }

        //Tags Have One Subject
        //Tag.SubjectId FK
        [ForeignKey("SubjectID")]
        public int SubjectId { get; set; }
        public Subject Subject { get; set; }

        //Tags Have One Or More Documents
        //(TagDocument Join Table)
        public List<TagDocument> TagDocuments { get; set; }

        //Tags Have One Or More Acronyms
        //TagAcronym Join Table
        public List<TagAcronym> TagAcronyms { get; set; }
    }

public class Acronym
    {
        [Key]
        public int Id { get; set; }

        [Required]
        [Display(Name = "Acronym")]
        [StringLength(50, ErrorMessage = "Acronym cannot be longer than 50 characters.")]
        public string Abbreviation { get; set; }

        [Required]
        [Display(Name = "Description")]
        [StringLength(100, ErrorMessage = "Description cannot be longer than 100 characters.")]
        public string Description { get; set; }

        [StringLength(250, ErrorMessage = "URL cannot be longer than 250 characters.")]
        public string URL { get; set; }

        //Acronyms Have One Or More AcronymOld
        //AcronymOld.AcronymId (FK)
        public List<AcronymOld> AcronymsOld { get; set; }

        //Acronyms Have One Or More Tags
        //TagAcronym Join Table
        
        public List<TagAcronym> TagAcronyms { get; set; }
    }

数据上下文

protected override void OnModelCreating(ModelBuilder modelBuilder) {
            //Tag and Subject one-to-one
            modelBuilder.Entity<Subject>()
                .HasOne(b => b.Tag)
                .WithOne(i => i.Subject)
                .HasForeignKey<Tag>(b => b.SubjectId);
            //Tag and TagDocument one-to-many
            modelBuilder.Entity<Tag>()
                .HasMany(t => t.TagDocuments)
                .WithOne(g => g.Tag)
                .HasForeignKey(g => g.TagId);
            //Acronym and AcronymsOld one-to-many
            modelBuilder.Entity<Acronym>()
                .HasMany(t => t.AcronymsOld)
                .WithOne(g => g.Acronym)
                .HasForeignKey(g => g.AcronymId);

            //Acronym and Tag many-to-many
            modelBuilder.Entity<TagAcronym>()
            .HasKey(t => new { t.TagId, t.AcronymId });

            modelBuilder.Entity<TagAcronym>()
                .HasOne(pt => pt.Tag)
                .WithMany(p => p.TagAcronyms)
                .HasForeignKey(pt => pt.TagId);

            modelBuilder.Entity<TagAcronym>()
                .HasOne(pt => pt.Acronym)
                .WithMany(t => t.TagAcronyms)
                .HasForeignKey(pt => pt.AcronymId);

        }

可以参考官方文档:https://docs.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#many-to-many

【讨论】:

    猜你喜欢
    • 2021-04-22
    • 2021-05-04
    • 1970-01-01
    • 2022-01-15
    • 2020-12-03
    • 2020-03-07
    • 2016-12-16
    • 2012-04-07
    相关资源
    最近更新 更多