与 Entity Framework Core 2.0 的一对零关系

Posted

技术标签:

【中文标题】与 Entity Framework Core 2.0 的一对零关系【英文标题】:One-to-Zero relationship with Entity Framework Core 2.0 【发布时间】:2018-03-08 12:54:16 【问题描述】:

我正在使用 C# 和 .NET Framework 4.7 将 Entity Framework 6.1.3 Code First 库迁移到 Entity Framework Core。

我一直在用 Google 搜索 Entity Framework Core,但我没有找到很多关于它的信息,所以我尝试自己做。

在 Entity Framework 6.1.3 上我有这个配置类:

using System.Data.Entity.ModelConfiguration;

namespace MyProject.Data.SqlServer.Configurations

    class AggregationChildrenConfiguration : EntityTypeConfiguration<AggregationChildren>
    
        public AggregationChildrenConfiguration()
        
            HasKey(ag_ch => ag_ch.AggregationChildrenId);

            HasRequired(ag_ch => ag_ch.Aggregation)
                .WithMany(ag => ag.AggregationChildren)
                .HasForeignKey(ag_ch => ag_ch.AggregationId);

            HasRequired(ag_ch => ag_ch.Code)
                .WithOptional(c => c.AggregationChild)
                .WillCascadeOnDelete(false);
        
    

我已经迁移到这个:

using DataLibrary;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace BusinessLibrary.Configurations

    class AggregationChildrenConfiguration : IEntityTypeConfiguration<AggregationChildren>
    
        public void Configure(EntityTypeBuilder<AggregationChildren> builder)
        
            builder.HasKey(ag_ch => ag_ch.AggregationChildrenId);

            builder.HasRequired(ag_ch => ag_ch.Aggregation)
                .WithMany(ag => ag.AggregationChildren)
                .HasForeignKey(ag_ch => ag_ch.AggregationId);

            builder.HasRequired(ag_ch => ag_ch.Code)
                .WithOptional(c => c.AggregationChild)
                .WillCascadeOnDelete(false);
        
    

但是builder没有HasRequired方法,我认为其他方法WithOptionalWithManyWillCascadeOnDelete也是。

我已经迁移到这个了,但不确定是否正确:

using DataLibrary;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;

namespace BusinessLibrary.Configurations

    class AggregationChildrenConfiguration : IEntityTypeConfiguration<AggregationChildren>
    
        public void Configure(EntityTypeBuilder<AggregationChildren> builder)
        
            builder.HasKey(ag_ch => ag_ch.AggregationChildrenId);

            builder.HasOne(ag_ch => ag_ch.Aggregation)
                .WithMany(ag => ag.AggregationChildren)
                .HasForeignKey(ag_ch => ag_ch.AggregationId)
                .IsRequired();

            builder.HasOne(ag_ch => ag_ch.Code)
                .WithOne(c => c.AggregationChild)
                .OnDelete(DeleteBehavior.SetNull);
        

我一直在检查 EntityTypeBuilder 文档,但我不知道我必须使用哪些方法,或者这是否是迁移到 Entity Framework Core 的正确方法。

这种关系不是一对零的:

builder.HasOne(ag_ch => ag_ch.Code)
    .WithOne(c => c.AggregationChild)
    .OnDelete(DeleteBehavior.SetNull);

在这个SO Answer 中说我必须将ForeignKey 设置为null,它会将其设置为可选,但我不能将Code.CodeId 设置为可为空。

【问题讨论】:

【参考方案1】:

EF6 设置正在创建一个所谓的One-To-One Shared Primary Key Association,其中依赖实体的 PK 也是主体实体的 FK。

EF Core 中的情况发生了变化。它自然支持共享 PK 和 FK 一对一关联。此外,可选/必需不用于确定关联的主体和从属端。 IsRequired 用于控制依赖实体是否可以在没有主体的情况下存在,并且仅适用于单独的 FK。而HasForeignKeyHasPrincipalKey 用于确定关联的主端和从属端,并映射从属FK 和主PK/备用键。

话虽如此,等效的EFC配置如下:

builder.HasOne(ag_ch => ag_ch.Code)
    .WithOne(c => c.AggregationChild)
    .HasForeignKey<AggregationChildren>(ag_ch => ag_ch.AggregationChildrenId)
    .OnDelete(DeleteBehavior.Restrict);

所以我们从使用HasOne + WithOne 定义关系开始。

然后HasForeignKey&lt;AggregationChildren&gt;(ag_ch =&gt; ag_ch.AggregationChildrenId) 告诉 EF (1) AggregationChildren 是关系的依赖端,以及 (2) PK AggregationChildrenId 也应该用作 FK。

最后,OnDelete(DeleteBehavior.Restrict) 是 EF6 WillCascadeOnDelete(false) 的 EFC 等效项。 ClientSetNullSetNull 等其他选项仅在依赖项具有单独的可选 FK 时适用,而共享 PK 关联则不是这种情况。

参考:Relationships

【讨论】:

感谢您的回答。有一点我不明白:你在哪里说从 Code 到 AggregationChildren 的关系是可选的? 这种情况下不需要。只有具有单独 FK 的依赖实体可能具有可选或必需的。请参阅IsRequired 方法的描述 - “配置这是否是必需的关系(即是否可以将外键属性分配为空)。”。 EF6 为不同的目的使用可选/必需的术语。在 EFC 中,默认情况下关系是可选的,除非您有明确的单独的不可为空的 FK 属性。 就我而言,这根本行不通。我试图在父母和孩子上定义HasForeignKey,它总是在父母身上结束。我尝试将子级指定为泛型类型,将父级指定为泛型类型,但它仍然总是以父级结束。 @ChaimEliyah 没办法。显然你做错了什么。首先,关系必须只有 1 个定义(以确保您没有创建冲突的关系配置)。其次,必须为子(从属)实体定义 FK。而已。 Parent(principal) 从来没有作为 FK。

以上是关于与 Entity Framework Core 2.0 的一对零关系的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework Core中的日志记录与拦截器

Entity Framework Core 中的日志记录与拦截器

Entity Framework Core 2 - 外键约束

Entity Framework Core 性能优化

Entity Framework Core 性能优化

Entity Framework Core 性能优化