多个外键EF Core 2.1代码首先在数据库中仅生成1

时间:2018-07-04 21:04:51

标签: asp.net-core entity-framework-core asp.net-core-2.1 ef-core-2.1 .net-core-2.1

我有以下模型:

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中的规定为CreationUserTerminationUser创建两个自引用前导键:

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

1 个答案:

答案 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);