I am using Visual Studio Community 2022 (64-bit, Version 17.1.0 Preview 1.1), ASP .Net 5 Razor Pages (Non-MVC), EF Core 5 and SQL Server.
I have two classes, that have a many to many relationship.
Class 1 (Tag):
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; }
}
Class 2 (Acronym):
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; }
}
Any Acronym can have many Tags, and a Tag can have many Acronyms.
I created a TagAcronym class to facilitate the creation of a Join Table in the database:
public class TagAcronym
{
public int TagId { get; set; }
public Tag Tag { get; set; }
public int AcronymId { get; set; }
public Acronym Acronym { get; set; }
}
}
When I create the Migration it attempts to create a TagAcronym and an AcronymTag table for reasons I cannot understand.
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");
}
Any help is appreciated. Thanks.
CodePudding user response:
you can use this model design :
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; }
}
datacontext
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);
}
You can refer to the official document:https://docs.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api,fluent-api-simple-key,simple-key#many-to-many
CodePudding user response:
The relationship between Tag and Acronym are many to many so EF will automatically create a mapper table for these tables with name (TagAcronym or AcronymTag) so you dont need to explicitly specify TagAcroymn table.