将现有代码优先模型和流畅的 aPI 配置从 Entity Framework 6 移植到 Entity Framework Core 2.0

Port existing code first models, and fluent aPI configuration from Entity Framework 6 to Entity Framework Core 2.0

假设在一个利用 Ef 6 的应用程序中,我有以下模型和流畅的api 配置,它们定义了车主和他拥有的 car/cars 之间的关系。 Car与CarOwner的关系是1对0或1,而CarOwner与Car的关系是1对0或多;

public class Car
{
    public int Id { get; set; }
    public string ChasisNumber { get; set; }
    public string EngineNumber { get; set; }

    public CarOwner CarOwner { get; set; }
}

public class CarOwner
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public IList<Car> Cars {get; set;}
}

对应fluentapi配置如下图

public class CarConfiguration : EntityTypeConfiguration<Car>
{
    HasKey(a => a.Id);
    Property(a => a.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
    HasOptional(x => x.CarOwner).WithMany(x => x.Cars).Map(x => x.MapKey("CarOwner_Id"));
}

public class CarOwnerConfiguration : EntityTypeConfiguration<CarOwner>
{
    HasKey(a => a.Id);
    Property(a => a.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
    HasMany(a => a.Cars).WithOptional(a => a.CarOwner);
}

在 EF Core 2.0 中,Car 模型发生了变化,因为需要将模型中的 CarOwner 外键指定为可为 null 的整数属性,但我不想那样做。

public class Car
{
    public int Id { get; set; }
    public string ChasisNumber { get; set; }
    public string EngineNumber { get; set; }

    public int? CarOwnerId { get;set; }
    public CarOwner CarOwner { get; set; }
}

有什么方法可以防止将 CarOwnerId 添加为 Car 实体中的引用键?我想确保我的模型与 Entity Framework 中的模型保持一致 6. 我不想对我的模型进行任何更改。我更愿意在流畅的 api 配置文件中进行所有必要的更改。

In EF Core 2.0 the Car model changes because of the need to specify the CarOwner foreign key in the Model as a nullable integer property

当然没有必要这么做。事实上,EF Core 让您可以更好地控制 shadow properties。只是默认的 FK 名称约定不同,因此为了保留 EF6 名称,您必须使用 fluent API.

显式配置它们

这里是原始模型的等效 EF Core 配置(w/o public int? CarOwnerId { get;set; } inside Car):

public class CarConfiguration : IEntityTypeConfiguration<Car>
{
    public void Configure(EntityTypeBuilder<Car> builder)
    {
        builder.HasKey(a => a.Id);
        builder.Property(a => a.Id).ValueGeneratedOnAdd().IsRequired();
        builder.HasOne(x => x.CarOwner)
            .WithMany(x => x.Cars)
            .HasForeignKey("CarOwner_Id") // <--
            .IsRequired(false);
    }
}

public class CarOwnerConfiguration : IEntityTypeConfiguration<CarOwner>
{
    public void Configure(EntityTypeBuilder<CarOwner> builder)
    {
        builder.HasKey(a => a.Id);
        builder.Property(a => a.Id).ValueGeneratedOnAdd().IsRequired();
    }
}

请注意,大多数流畅的配置都是多余的,可以省略,因为它们是 EF 的常规默认设置。关系配置也应该在一个地方以避免设置冲突 - 关系总是有两个端点,所以逻辑上它不是两个实体中任何一个的一部分(不适合实体类型配置分离)。

实现相同映射的最小流畅配置是这样的(完全不使用实体类型配置):

modelBuilder.Entity<Car>()
    .HasOne(x => x.CarOwner)
    .WithMany(x => x.Cars)
    .HasForeignKey("CarOwner_Id");