【问题标题】:EF Core: Using ID as Primary key and foreign key at same timeEF Core:同时使用 ID 作为主键和外键
【发布时间】:2021-09-19 15:26:06
【问题描述】:

我有两个实体,ProspectPerson,我想做的是使用Prospect.ID 作为Prospect 表的主键和PersonID 的外键,我的想法是对两个实体使用相同的 ID,而不需要在我的 Prospect 实体上使用 PersonID。当潜在客户保存在数据库中时,它会尝试保存 PersonID,即使我的 Prospect 实体上没有此属性,我想知道 EF 核心是否支持这种关系。

这是我在模型构建器上得到的:

modelBuilder.Entity<ProspectDto>(builder => { builder.ToTable("Prospects"); builder.HasKey(prospect => prospect.ID); });

modelBuilder.Entity<PersonDto>(builder => { builder.HasOne(p => p.Prospect).WithOne().HasForeignKey<ProspectDto>(pe => pe.ID); });

这是在数据库上执行的内容:

INSERT INTO [Prospects] ([ID], [PersonID]) VALUES (@p421, @p422)

PersonDto:

public class PersonDto : DtoBase
{
    public PersonDto()
    {
        
    }
  
    public ProspectDto Prospect { get; set; }
}

ProspectDto:

public class ProspectDto : DtoBase
{
    public ProspectDto()
    {

    }

    public PersonDto Person { get; set; } = new PersonDto();
}

DtoBase:

public abstract class DtoBase
{
    public Guid ID { get; protected set; }
}

谢谢。

【问题讨论】:

  • 请出示ProspectDtoPersonDto类声明(您可以跳过数据字段,与问题无关)。
  • @Dmitry 更新
  • 嗯,看不到任何ID 字段...猜猜它可能存在于DtoBase...您能否提供有关您的模型的所有信息,与问题相关?
  • @Dmitry 更新

标签: c# entity-framework-core ef-model-builder


【解决方案1】:

仅使用属性,不使用 FluentAPI:

public abstract class DtoBase
{
    [Key]
    public Guid ID { get; protected set; }
}

public class PersonDto : DtoBase
{
    [InverseProperty("Person")]
    public ProspectDto Prospect { get; set; }
}

public class ProspectDto : DtoBase
{
    [ForeignKey("ID")]           // "magic" is here
    public PersonDto Person { get; set; } = new PersonDto();
}

我不知道 FluentAPI 中的 ForeignKey 是什么。所有其他(Key 和 InverseProperty)都是可配置的,但为什么要使用两种方法而不是一种。

上面的代码生成以下迁移代码:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "Persons",
        columns: table => new
        {
            ID = table.Column<Guid>(nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Persons", x => x.ID);
        });

    migrationBuilder.CreateTable(
        name: "Prospects",
        columns: table => new
        {
            ID = table.Column<Guid>(nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Prospects", x => x.ID);
            table.ForeignKey(
                name: "FK_Prospects_Persons_ID",
                column: x => x.ID,
                principalTable: "Persons",
                principalColumn: "ID",
                onDelete: ReferentialAction.Cascade);
        });
}

看起来非常接近您的需要。

【讨论】:

  • 完美运行,谢谢。另一个问题,你知道使用 fluent API 的等价物吗?
  • 对此没有更多的支持感到惊讶 - 效果很好,是一个明显的例子。干杯!
  • 非常感谢。我更喜欢属性而不是 FluentAPI。
【解决方案2】:

这是 @dmitry 解决方案的 FluentAPI 等效项:

// Model classes:
public abstract class DtoBase
{
    public Guid ID { get; protected set; }
}

public class PersonDto : DtoBase
{
    public ProspectDto Prospect { get; set; }
}

public class ProspectDto : DtoBase
{
    public PersonDto Person { get; set; } = new PersonDto();
}

-------------------------------------------------------------------

// DbContext's OnModelCreating override:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<ProspectDto>().HasOne(p => p.Person).WithOne().HasForeignKey<ProspectDto>(p => p.ID);
}

【讨论】:

  • Dominik,你忘记了modelBuilder后面的.Entity()。然后它运作良好。所以,我会在修复后投票... ;-)
  • @Tolbxela 你是对的,谢谢!刚刚修好了。
【解决方案3】:

如果将关系建模为一对一,EF 将自动使用主体的 PK 作为依赖的 FK。

 ModelBuilder.Entity<ProspectDto>().HasRequired(p => p.Person).WithRequiredDependent();

请注意,ProspectDto 在 DB 上仍然有一个 ID 列(继承自 DtoBase),但 FK 关系将在 ProspectDto.IDPersonDto.ID 之间,并且应该没有 ProspectDto.PersonId 列。

【讨论】:

  • HasRequired() 在 ef 核心上不可用。
  • 抱歉,应该更仔细地阅读您的问题,此代码来自 EF 6.1 项目。
猜你喜欢
  • 2018-05-03
  • 2018-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多