c# - 具有自定义列名的同一个表的 ForeignKey
问题描述
我有一个模型User
:
public class User
{
[Key]
public int IDUser { get; set; }
[Required]
public string Forename { get; set; }
[Required]
public string Name { get; set; }
public int? IDUser_CreatedBy { get; set; }
public User User_CreatedBy { get; set; }
}
用户当然可以将其创建者 ( User_CreatedBy
) 及其 ID ( IDUser_CreatedBy
) 放在同一个表中,但我希望有机会将其保留为空值(User
创建者未知)。这就是为什么IDUser_CreatedBy
具有int?
可为空的类型。
我不知道如何设置我的 fluent API 以便将该外键绑定IDUser_CreatedBy
到同一张表中的主键IDUser
。
我知道,如果我IDUser_CreatedBy
从该模型中删除外键并添加新的迁移,那么 EF 核心将为我隐含地生成影子属性外键,但我希望有机会User
使用自定义创建的列更新我的稍后(在 MVC 控制器中)IDUser_CreatedBy
并能够为我自己命名该列。此外,我不想要那个影子属性,因为我无法控制该列的命名。
我怎样才能做到这一点?
编辑
@IvanStoev - 感谢您的回答,但您的示例没有为我生成有效的迁移代码:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users");
migrationBuilder.RenameColumn(
name: "CreatedByIDUser",
table: "Users",
newName: "UserIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_CreatedByIDUser",
table: "Users",
newName: "IX_Users_UserIDUser");
migrationBuilder.AddColumn<int>(
name: "IDUser_CreatedBy",
table: "Users",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Users_IDUser_CreatedBy",
table: "Users",
column: "IDUser_CreatedBy");
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_IDUser_CreatedBy",
table: "Users",
column: "IDUser_CreatedBy",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_UserIDUser",
table: "Users",
column: "UserIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_IDUser_CreatedBy",
table: "Users");
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_UserIDUser",
table: "Users");
migrationBuilder.DropIndex(
name: "IX_Users_IDUser_CreatedBy",
table: "Users");
migrationBuilder.DropColumn(
name: "IDUser_CreatedBy",
table: "Users");
migrationBuilder.RenameColumn(
name: "UserIDUser",
table: "Users",
newName: "CreatedByIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_UserIDUser",
table: "Users",
newName: "IX_Users_CreatedByIDUser");
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users",
column: "CreatedByIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
它确实生成了我想要的 ForeignKey 列 ( IDUser_CreatedBy
) 和该键列的有效索引 ( IX_Users_IDUser_CreatedBy
),但它还添加了另一个 ForeignKey ( UserIDUser
),我猜它是一个影子属性。因此,我有 2 个不同的 ForeignKey 列,它们引用同一个IDUser
表中的一个 Primerykey 列 ()。在我的例子中,迁移实际上将旧列 ( CreatedByIDUser
) 重命名为新列 (),UserIDUser
这是我之前的影子属性 ForeignKey 列的残余。我正在寻找的是迁移将完全摆脱以前的影子属性并只引入一个新的 ForeignKey 列 ( IDUser_CreatedBy
)。有什么建议么 ?
编辑 2
@viveknuna - 谢谢你的例子,但它也不适合我。
迁移看起来像这样:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users");
migrationBuilder.RenameColumn(
name: "CreatedByIDUser",
table: "Users",
newName: "User_CreatedByIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_CreatedByIDUser",
table: "Users",
newName: "IX_Users_User_CreatedByIDUser");
migrationBuilder.AddColumn<int>(
name: "IDUser_CreatedBy",
table: "Users",
nullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_User_CreatedByIDUser",
table: "Users",
column: "User_CreatedByIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Users_User_CreatedByIDUser",
table: "Users");
migrationBuilder.DropColumn(
name: "IDUser_CreatedBy",
table: "Users");
migrationBuilder.RenameColumn(
name: "User_CreatedByIDUser",
table: "Users",
newName: "CreatedByIDUser");
migrationBuilder.RenameIndex(
name: "IX_Users_User_CreatedByIDUser",
table: "Users",
newName: "IX_Users_CreatedByIDUser");
migrationBuilder.AddForeignKey(
name: "FK_Users_Users_CreatedByIDUser",
table: "Users",
column: "CreatedByIDUser",
principalTable: "Users",
principalColumn: "IDUser",
onDelete: ReferentialAction.Restrict);
}
它将我的剩余影子属性 ForeignKey 重命名为新名称,但它保留了该影子属性。迁移还添加了IDUser_CreatedBy
不是 ForeignKey 的新列(该列没有AddForeignKey
和CreateIndex
方法)。
编辑 3
@Ivan Stoev - 你是对的。我没有提交整个模型,因为我认为它不会对结果产生影响,但现在很明显它有...... :) 首先 - 我确实创建了一个全新的命令行项目并设法将正确的迁移搭建为你说。然后我意识到我的模型有另一个属性,public List<User> UsersAdded { get; set; }
它描述了由该特定添加的所有用户User
。这就是罪魁祸首。它将新列添加UserIDUser
到新创建的迁移中。所以最后一个问题是:我怎样才能用那个新属性实现我所需要的一切public List<User> UsersAdded { get; set; }
?因为我想有机会在我的 MVC 控制器中包含User
这个User
创建的集合。User
作为一种形式,我提交了我的整个模型(这次是正确的):
public class User
{
[Key]
public int IDUser { get; set; }
[Required]
public string Forename { get; set; }
[Required]
public string Name { get; set; }
public string AvatarPath { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string Password { get; set; }
public bool IsWebUser { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public int? IDUser_CreatedBy { get; set; }
public User User_CreatedBy { get; set; }
public List<User> UsersAdded { get; set; }
}
解决方案
EF Core fluent API 让您可以完全控制命名表列,无论您是使用显式模型属性还是影子模型属性。非常规的外键属性通过关系配置HasForeignKey
的 fluent API 进行映射。
您的实体模型属于具有显式 FK 属性类别的单一导航属性,可以像这样映射:
modelBuilder.Entity<User>()
.HasOne(e => e.User_CreatedBy) // reference navigation property
.WithMany() // no collection navigation property
.HasForeignKey(e => e.IDUser_CreatedBy); // foreign key property
推荐阅读
- reactjs - 带有功能组件的功能道具 - 不是功能(React + Typescript)
- c# - foreach 循环中的多线程
- docker - Docker secret 挂载一个空字符串
- kotlin - Mapbox Android:调整背景层的不透明度
- python - SqlAlchemy 时间戳的区别
- asp.net - 如何在身份服务器 4 中获取设备代码流的用户代码
- c++ - 结构变量成员后的花括号是什么意思?
- jquery - 在荷兰甲酸盐中反击 jquery 不起作用
- python-3.x - tf_encrypted.player如何配置?
- c++ - VC++ 成员函数中声明的静态变量的可见性是什么?