首页 > 其他分享 >EFCore 一对一 实体关系

EFCore 一对一 实体关系

时间:2024-05-07 10:55:42浏览次数:24  
标签:set get 一对一 实体 Blog EFCore BlogHeader public

一对一 实体关系

当一个实体与最多一个其他实体关联时,将使用一对一关系。 例如,Blog 有一个 BlogHeader,并且 BlogHeader 属于单个 Blog

必需的一对一

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public BlogHeader? Header { get; set; } // Reference navigation to dependent
}

// Dependent (child)
public class BlogHeader
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

一对一关系由以下部分组成:

  • 主体实体上的一个或多个主键或备用键属性。 例如 Blog.Id
  • 依赖实体上的一个或多个外键属性。 例如 BlogHeader.BlogId
  • (可选)引用依赖实体的主体实体上的引用导航。 例如 Blog.Header
  • (可选)引用主体实体的依赖实体上的引用导航。 例如,BlogHeader.Blog

提示

一对一关系的哪一端应是主体实体,哪一端应是依赖实体,这并不总是显而易见的。 请注意以下事项:

  • 如果两种类型的数据库表已存在,则具有外键列的表必须映射到依赖类型。
  • 如果某个类型在逻辑上不能在没有另一个类型的情况下存在,则它通常是依赖类型。 例如,对于不存在的博客,它的标题是没有意义的,因此 BlogHeader 自然是依赖类型。
  • 如果存在自然的父/子关系,则子级通常是依赖类型。

因此,对于此示例中的关系:

  • 外键属性 BlogHeader.BlogId 不可为空。 这会使关系成为“必需”关系,因为每个依赖实体 (BlogHeader) 必须与某个主体实体 (Blog) 相关,而其外键属性必须设置为某个值。
  • 这两个实体都有指向关系另一端的相关实体的导航。

提示

具有两个导航的关系(一个是从依赖实体到主体实体,一个是从主体实体到依赖实体)称为双向关系。

此关系按约定发现。 即:

  • Blog 作为关系中的主体实体被发现,BlogHeader 作为依赖实体被发现。
  • BlogHeader.BlogId 作为引用主体实体的 Blog.Id 主键的依赖实体的外键被发现。 由于 BlogHeader.BlogId 不可为空,所以发现这一关系是必需的。
  • Blog.BlogHeader 作为引用导航被发现。
  • BlogHeader.Blog 作为引用导航被发现。

重要

使用 C# 可为空引用类型时,如果外键属性可为空,则从依赖实体到主体实体的导航必须可为空。 如果外键属性不可为空,则导航可以为空,也可以不为空。 在这种情况下,BlogHeader.BlogId 和 BlogHeader.Blog 皆不可为空。 = null!; 构造用于将此标记为 C# 编译器的有意行为,因为 EF 通常会对 Blog 实例进行设置,并且对于完全加载的关系,它不能为空。 有关详细信息,请参阅使用可为空引用类型

对于未按约定发现关系的导航、外键或必需/可选性质的情况,可以显式配置这些内容。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasOne(e => e.Header)
        .WithOne(e => e.Blog)
        .HasForeignKey<BlogHeader>(e => e.BlogId)
        .IsRequired();
}

  在上面的示例中,关系的配置将启动主体实体类型 (Blog)。 与所有关系一样,它完全等效于从依赖实体类型 (BlogHeader) 开始。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<BlogHeader>()
        .HasOne(e => e.Blog)
        .WithOne(e => e.Header)
        .HasForeignKey<BlogHeader>(e => e.BlogId)
        .IsRequired();
}

与另一个选项相比,这两个选项并没有什么优势:它们都会导致完全相同的配置。

 提示

没有必要对关系进行两次配置,即先从主体实体开始,又从依赖实体开始。 此外,尝试单独配置关系的主体实体和依赖实体通常不起作用。 选择从一端或另一端配置每个关系,然后只编写一次配置代码。

可选的一对一

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public BlogHeader? Header { get; set; } // Reference navigation to dependent
}

// Dependent (child)
public class BlogHeader
{
    public int Id { get; set; }
    public int? BlogId { get; set; } // Optional foreign key property
    public Blog? Blog { get; set; } // Optional reference navigation to principal
}

  这与上一个示例相同,只不过外键属性和到主体实体的导航现在可为空。 这会使关系成为“可选”关系,因为依赖实体 (BlogHeader) 不能通过将其外键属性和导航设置为 null 来与任何主体 (Blog) 相关。

重要

使用 C# 可为空引用类型时,如果外键属性可为空,则从依赖实体到主体实体的导航属性必须可为空。

如前所述,此关系按约定发现。 对于未按约定发现关系的导航、外键或必需/可选性质的情况,可以显式配置这些内容。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasOne(e => e.Header)
        .WithOne(e => e.Blog)
        .HasForeignKey<BlogHeader>(e => e.BlogId)
        .IsRequired(false);
}

具有主键到主键关系的必需的一对一

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public BlogHeader? Header { get; set; } // Reference navigation to dependent
}

// Dependent (child)
public class BlogHeader
{
    public int Id { get; set; }
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}  

与一对多关系不同,一对一关系的依赖端可以将其主键属性用作外键属性。 这通常称为 PK 到 PK 关系。 仅当主体类型和依赖类型具有相同的主键类型,并且始终需要生成的关系时才有可能,因为依赖类型的主键不可为空。

必须配置未按约定发现外键的任何一对一关系,以指示关系的主体端和依赖端。 这通常是使用对 HasForeignKey 的调用来完成的。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasOne(e => e.Header)
        .WithOne(e => e.Blog)
        .HasForeignKey<BlogHeader>();
}

如果对 HasForeignKey 的调用中未指定任何属性,并且主键适用,则将其用作外键。 对于未按约定发现关系的导航、外键或必需/可选性质的情况,可以显式配置这些内容。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasOne(e => e.Header)
        .WithOne(e => e.Blog)
        .HasForeignKey<BlogHeader>(e => e.Id)
        .IsRequired();
}

具有备用键的一对一

在到目前为止的所有示例中,依赖实体上的外键属性被约束为主体实体上的主键属性。 外键可以改为被约束为不同的属性,该属性随后成为主体实体类型的备用键。 例如:

// Principal (parent)
public class Blog
{
    public int Id { get; set; }
    public int AlternateId { get; set; } // Alternate key as target of the BlogHeader.BlogId foreign key
    public BlogHeader? Header { get; set; } // Reference navigation to dependent
}

// Dependent (child)
public class BlogHeader
{
    public int Id { get; set; }
    public int BlogId { get; set; } // Required foreign key property
    public Blog Blog { get; set; } = null!; // Required reference navigation to principal
}

  此关系不是按约定发现的,因为 EF 始终按照约定创建与主键的关系。 可以使用对 HasPrincipalKey 的调用在 OnModelCreating 中显式配置它。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasOne(e => e.Header)
        .WithOne(e => e.Blog)
        .HasPrincipalKey<Blog>(e => e.AlternateId);
}

  HasPrincipalKey 可与其他调用结合使用,以显式配置导航、外键属性和必需/可选性质。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasOne(e => e.Header)
        .WithOne(e => e.Blog)
        .HasPrincipalKey<Blog>(e => e.AlternateId)
        .HasForeignKey<BlogHeader>(e => e.BlogId)
        .IsRequired();
}

  

自引用一对一

在前面的所有示例中,主体实体类型与依赖实体类型有所不同。 情况不一定如此。 例如,在下面的类型中,每个 Person 类型都可选择与另一个 Person 相关。

public class Person
{
    public int Id { get; set; }

    public int? HusbandId { get; set; } // Optional foreign key property
    public Person? Husband { get; set; } // Optional reference navigation to principal
    public Person? Wife { get; set; } // Reference navigation to dependent
}

  此关系按约定发现。 对于未按约定发现关系的导航、外键或必需/可选性质的情况,可以显式配置这些内容。 例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()
        .HasOne(e => e.Husband)
        .WithOne(e => e.Wife)
        .HasForeignKey<Person>(e => e.HusbandId)
        .IsRequired(false);
}

备注

对于一对一自引用关系,由于主体实体类型和依赖实体类型相同,指定包含外键的类型不会阐明依赖端。 在本例中,从依赖实体到主体实体以 HasOne 点为单位指定的导航,以及从主体实体到依赖实体以 WithOne 点为单位指定的导航。

  参考:https://learn.microsoft.com/zh-cn/ef/core/modeling/relationships/one-to-one

  

  

  

 

 

标签:set,get,一对一,实体,Blog,EFCore,BlogHeader,public
From: https://www.cnblogs.com/friend/p/18176728

相关文章

  • EFCore 迁移异常解决方案
    添加迁移时显示错误:Bothrelationshipsbetween'WorkCenter.Factory'and'Factory'andbetween'WorkCenter'and'Factory.WorkCenters'coulduse{'FactoryId'}astheforeignkey.Toresolvethis,configuretheforeig......
  • NVIDIA的人形机器人的基础模型Project GR00T已在实体机器人上进行展示
    原文地址:https://blogs.nvidia.com/blog/isaac-generative-ai-manufacturing-logistics/项目GR00T为人型机器人开发谢幕在GTC上展示,由GR00T驱动的人型机器人可以接受多模态指令——文本、视频和演示——以及它们之前的交互,以产生机器人所需的动作。GR00T在来自不同公司的四个......
  • EPAI手绘建模APP导入导出、实体
    4、建模工具栏图 99 建模工具栏-1 图 100 建模工具栏-2(1) 导入导出图 101 导入导出工具栏① 导入brep、iges、step三种cad常用模型文件(autocad、ug、solidwork、freecad等),导入obj、stl、glb、x3d四种非cad建模建模软件常用的三角网格模型文件(3dmax、maya等......
  • efcore全局查询过滤器
    我们删除实体时,平常不需要物理删除,而是软删除,软删除有什么好处呢?它能够在下次创建实体时快速恢复实体的信息,平时我们使用IsDeleted字段来代表软删除,以下是一个示例publicclassPost{publicintPostId{get;set;}publicstringTitle{get;set;}public......
  • efcore 执行原生sql语句
    EntityFrameworkCore(EFCore)执行原生SQL查询需要返回查询结果使用FromSqlRaw()方法:这是EFCore提供的一种执行原生SQL查询的方式。您可以将SQL查询直接嵌入到代码中,并将结果作为实体对象返回。以下是一个示例,演示如何执行原生SQL查询并将结果映射到实体对象:v......
  • 一个通用的SpringBoot项目响应实体类Response
    packagecom.luky.vo;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importlombok.ToString;importorg.springframework.http.HttpStatus;@Data@ToString@AllArgsConstructor@NoArgsConstructorpublicclassResponse&......
  • C# 将实体2的值动态赋值给实体1(名称一样的属性进行赋值)
     ///<summary>///将实体2的值动态赋值给实体1(名称一样的属性进行赋值)///</summary>///<paramname="model1">实体1</param>///<paramname="model2">实体2</param>///<retur......
  • 数据库设计 外键设计 关联表查询 linq efcore
    数据库的设计实体之间的关系图实体EleOrderRowItem.cspublicclassEleOrderRowItem:EleEntity{publicstring?Xxx{get;set;}//外键:一个rowItem属于一个rowpubliclongRowId{get;set;}publicrequiredEleOrderRowRow{get;set;}}......
  • 解决 java 实体中用 LocalDateTime 在转换时候报错 Error attempting to get column
    java中的实体类用到了LocalDateTime类型。在转换时候报错Errorattemptingtogetcolumn‘XXX’fromresultset.Cause:java.sql.解决方法最为简单。是因为com.alibaba的版本问题。切换版本号到1.1.22即可消除问题<dependency><groupId>com.alibaba</gro......
  • 通过写入实体进行导出
    @GetMapping("/exportScore")publicvoidexportScore(HttpServletResponseresponse)throwsException{//从数据库查询出所有的数据List<Score>list=scoreService.getScoreAll();//通过工具类创建writer写出到磁盘路径//Exc......