我有以下模型:
public class User : AuditedModel
{
public string Login { get; }
public string PasswordHash { get; }
public User(string login, string password, User creationUser) : base(creationUser)
{
Login = login;
PasswordHash = GeneratePasswordHash(password);
}
protected User(int id, DateTime creationDate, DateTime? terminationDate, string login, string passwordHash) : base(id, 0, creationDate)
{
Login = login;
PasswordHash = passwordHash;
}
}
public class AuditedModel : BaseModel
{
protected AuditedModel(User creationUser)
{
CreationUser = creationUser;
CreationDate = DateTime.UtcNow;
}
public User CreationUser { get; protected set; }
public DateTime CreationDate { get; }
public User TerminationUser { get; protected set; }
public DateTime? TerminationDate { get; }
}
public class BaseModel
{
public int Id { get;}
protected BaseModel()
{
}
public BaseModel(int id)
{
Id = id;
}
}
EF核心代码首先应按照Fluent API中的规定为CreationUser
和TerminationUser
创建两个自引用前导键:
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable(nameof(User));
builder.HasKey(u => u.Id);
builder.Property(u => u.Id).ValueGeneratedOnAdd();
builder.Property(u => u.Login)
.IsRequired();
builder.Property(u => u.PasswordHash);
builder.Property(u => u.CreationDate);
builder.Property(u => u.TerminationDate);
builder.HasOne(u => u.TerminationUser)
.WithOne()
.HasForeignKey<User>(u => u.Id)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne(u => u.CreationUser)
.WithOne()
.IsRequired()
.HasForeignKey<User>(u => u.Id)
.OnDelete(DeleteBehavior.Restrict);
}
}
我打算为此项目使用迁移,所以我将显示迁移输出,该输出反映在数据库上:
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.EnsureSchema(
name: "public");
migrationBuilder.CreateTable(
name: "User",
schema: "public",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
CreationDate = table.Column<DateTime>(nullable: false),
TerminationUserId = table.Column<int>(nullable: true),
TerminationDate = table.Column<DateTime>(nullable: true),
Login = table.Column<string>(nullable: false),
PasswordHash = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_User", x => x.Id);
table.ForeignKey(
name: "FK_User_User_TerminationUserId",
column: x => x.TerminationUserId,
principalSchema: "public",
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_User_TerminationUserId",
schema: "public",
table: "User",
column: "TerminationUserId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "User",
schema: "public");
}
}
如图所示,即使TerminationUserId
导航设置为必填,也只有CreationUser
ForeignKey列。
I'm using:
- Npgsql.EntityFrameworkCore.PostgreSQL 2.1.1
- Microsoft.NETCore.App 2.1.0
- Microsoft.EntityFrameworkCore.Tools.DotNet 2.0.3
- Microsoft.EntityFrameworkCore.Design 2.1.1
- Microsoft.VisualStudio.Web.CodeGeneration.Tools 2.0.4
答案 0 :(得分:2)
令我惊讶的是,TerminationUserId
外键列是在您的模型中不存在的情况下创建的。如果要同时创建这两个外键列,则需要按如下所示将它们添加到模型中:
public class AuditedModel : BaseModel
{
protected AuditedModel(User creationUser)
{
CreationUser = creationUser;
CreationDate = DateTime.UtcNow;
}
public int CreationUserId { get; protected set; }
public User CreationUser { get; protected set; }
public DateTime CreationDate { get; }
public int? TerminationUserId { get; protected set; }
public User TerminationUser { get; protected set; }
public DateTime? TerminationDate { get; }
}
然后在您的Fluent API映射中:
builder.HasOne(u => u.TerminationUser)
.WithOne()
.HasForeignKey<User>(u => u.TerminationUserId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne(u => u.CreationUser)
.WithOne()
.IsRequired()
.HasForeignKey<User>(u => u.CreationUserId)
.OnDelete(DeleteBehavior.Restrict);