实体框架与有时独立的类一对一

本文关键字:一对一 独立 框架 实体 | 更新日期: 2023-09-27 17:55:00

我有一个父类ComponentDesign

public class ComponentDesign
{
    public string Name { get; set; }
    public virtual JobFile DesignFile { get; set; }
    public int? DesignFileId { get; set; }
    public Pdf PdfFile { get; set; }
    public int? PdfFileId { get; set; }
    public JobFile SealedPdfFile { get; set; }
    public int? SealedPdfFileId { get; set; }
    public int Id { get; set; }
    public int JobId { get; set; }
}

还有一个子类JobFile(其中Pdf是子类(:

public class JobFile
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public ComponentDesign ComponentDesign { get; set; }
    public int? ComponentDesignId { get; set; }
    public int? JobId { get; set; }
}

这些类使用实体框架存储在关系数据库中。我希望关系的双方都有导航属性,以便我可以随意说componentDesign.PdfFilejobFile.ComponentDesign

ComponentDesign 中类型JobFile的每个属性都是可选的,并且 JobFile will only ever belong to one ComponentDesign . However, a JobFile may be free-standing, not belonging to any ComponentDesign (so jobFile.ComponentDesign' 将为 null(。

我正在努力了解如何使用 Fluent API 来配置这种关系。它是一对一的。是否可以在关系的两端都有导航属性?请记住,JobFile可以是独立的(因此jobFile.ComponentDesign并不总是相关的(,因此JobFile属于ComponentDesign,有些不属于。我觉得我最接近的是:

modelBuilder.Entity<ComponentDesign>()
            .HasOptional(componentDesign => componentDesign.DesignFile)
            .WithRequired(jobFile => jobFile.ComponentDesign);

但在我看来,这似乎表明jobFile.ComponentDesign总是需要的,但事实并非如此。我犹豫是否要尝试一下,因为它会产生一些实质性的迁移,所以我想先获得输入。在这种情况下,我的 Fluent API 配置应该是什么样子的?

实体框架与有时独立的类一对一

只是为了让我理解这些关系:

ComponentDesign -> JobFile = 可选。

JobFile -> ComponentDesign = 可选。

这是从零到一到零或一([0/1]-[0/1](的关系。

这可以通过以下方式实现,使用 fluent API 中的 .WithOptionalPrincipal 方法。在 1-0 的关系中,很明显哪一端是主要终点;与 1-∞ 关系相同。∞∞关系没有主体端,因为创建了控制每个关系之间关系的隐藏表。对于 0/1-0/1 或 1-1 关系,这并不明显,因此您必须告诉数据库将哪一端用作关系的主要端。在许多其他事情中,Pricipal 负责启动和维护表之间的关系。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure ComponentDesign & JobFile entity
    modelBuilder.Entity<ComponentDesign>()
        // Mark JobFile property optional in ComponentDesign entity.
        .HasOptional(cd => cd.DesignFile)
        // Mark ComponentDesign property optional in JobFile entity.
        .WithOptionalPrincipal(jf => jf.ComponentDesign); 
}

或者,您可以为每个实体创建一个 EntityTypeConfiguration<> 类来分离关系(如果有很多要排序(。虽然这确实分散了关系,但它更具可扩展性,因为一旦上下文配置为这样做,就可以通过 MEF 注入这些配置类。只是对未来发展的一个想法。

如果要从 JobFile 端配置关系,则应使用 .WithOptionalDependent 来正确设置导航,而不是 .WithOptionalPrincipal 。这完全取决于您从哪一端配置关系。ComponentDesign实体对JobFile实体的依赖远远超过JobFile实体对ComponentDesign实体的依赖;因此,应将其配置为主体。

如上面的评论之一所述,复杂属性应使用 virtual 关键字进行修饰。这种延迟加载属性,并且,当类被初始化时,它将初始值设置为 null

将数据库克隆到测试服务器,以解决这一个问题,然后在生产模型上实施更改;这样在迁移数据库时就不会丢失数据。