如何在EF Core模型类中修改外键关联至UniColumn而非主键
问题描述
现有以下EF Core模型类:
public enum Roster { None, One, Two, Three, Four } [Index(nameof(UniColumn), IsUnique = true)] internal class RowRosterEnum { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] [EnumDataType(typeof(Roster))] public Roster RosterEnum { get; set; } public Roster UniColumn { get; set; } } internal class RowRoster { [Key] [ForeignKey(nameof(RowRosterEnum))] public Roster RId { get; set; } public string? Name { get; set; } public RowRosterEnum RowRosterEnum { get; set; } }
创建迁移时生成的代码如下:
migrationBuilder.CreateTable( name: "TableRosterEnum", columns: table => new { RosterEnum = table.Column<int>(type: "int", nullable: false), UniColumn = table.Column<int>(type: "int", nullable: false) }, constraints: table => { table.PrimaryKey("PK_TableRosterEnum", x => x.RosterEnum); }); migrationBuilder.CreateTable( name: "TableRoster", columns: table => new { RId = table.Column<int>(type: "int", nullable: false), Name = table.Column<string>(type: "nvarchar(max)", nullable: true) }, constraints: table => { table.PrimaryKey("PK_TableRoster", x => x.RId); table.ForeignKey( name: "FK_TableRoster_TableRosterEnum_RId", column: x => x.RId, principalTable: "TableRosterEnum", principalColumn: "RosterEnum", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_TableRosterEnum_UniColumn", table: "TableRosterEnum", column: "UniColumn", unique: true);
需求:修改模型类,使RowRoster的外键关联到RowRosterEnum的UniColumn(即迁移代码中principalColumn为"UniColumn"),同时保留RosterEnum作为RowRosterEnum的主键。
解决方案
EF Core默认会将外键关联到主表的主键列,要实现需求需手动指定主表的关联列,以下两种方式均可实现:
方式一:使用数据注解修改模型
通过显式声明外键属性和关联列来调整关系:
public enum Roster { None, One, Two, Three, Four } [Index(nameof(UniColumn), IsUnique = true)] internal class RowRosterEnum { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] [EnumDataType(typeof(Roster))] public Roster RosterEnum { get; set; } public Roster UniColumn { get; set; } // 添加导航属性,辅助EF Core识别关联关系 public ICollection<RowRoster> RowRosters { get; set; } = new List<RowRoster>(); } internal class RowRoster { [Key] public Roster RId { get; set; } public string? Name { get; set; } // 指定外键关联到RowRosterEnum的UniColumn列 [ForeignKey(nameof(UniColumn))] public RowRosterEnum RowRosterEnum { get; set; } // 声明对应主表UniColumn的外键属性 public Roster UniColumn { get; set; } }
方式二:使用Fluent API配置(推荐,关系配置更清晰)
保持模型类简洁,在DbContext的OnModelCreating方法中配置关联规则:
修改后的模型类
public enum Roster { None, One, Two, Three, Four } [Index(nameof(UniColumn), IsUnique = true)] internal class RowRosterEnum { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] [EnumDataType(typeof(Roster))] public Roster RosterEnum { get; set; } public Roster UniColumn { get; set; } public ICollection<RowRoster> RowRosters { get; set; } = new List<RowRoster>(); } internal class RowRoster { [Key] public Roster RId { get; set; } public string? Name { get; set; } public RowRosterEnum RowRosterEnum { get; set; } public Roster UniColumn { get; set; } }
在DbContext中配置关系
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<RowRoster>() .HasOne(r => r.RowRosterEnum) .WithMany(e => e.RowRosters) .HasForeignKey(r => r.UniColumn) // 指定RowRoster的外键列 .HasPrincipalKey(e => e.UniColumn); // 指定RowRosterEnum的关联列 }
修改后迁移代码效果
重新生成迁移后,外键部分会变为:
table.ForeignKey( name: "FK_TableRoster_TableRosterEnum_UniColumn", column: x => x.UniColumn, principalTable: "TableRosterEnum", principalColumn: "UniColumn", onDelete: ReferentialAction.Cascade);
此时RowRoster表会新增UniColumn列作为外键关联到RowRosterEnum的UniColumn,RId依然是RowRoster的主键,RosterEnum也保留为RowRosterEnum的主键。
内容的提问来源于stack exchange,提问作者user9163823
相关产品推荐
相关产品推荐

