Entity Framework配置关系

目录
  • 一、Has方法与With方法
    • 1、Has方法:
    • 2、With方法:
  • 二、一对一关系:
    • 1、DataAnnotations数据标注的方式
    • 2、Fluent API方式
      • (1)1:0..1关系
      • (2)1:1 关系
  • 三、一对多关系:
    • 1、DataAnnotations方式
    • 2、更改外键的nullable属性和外键的名字
      • 1、使用Data Annotations指定外键:
      • 2、用Fluent API指定外键:
    • 3、对同一实体多个引用的情况
    • 4、级联删除
  • 四、多对多关系
    • 指定表名

一、Has方法与With方法

如:A类必须包含B类一个不为null的实例,而B类可选择时候包含A类一个实例。

A.HasRequired(a => a.B).WithOptional(b => b.A);

1、Has方法:

  • HasOptional:前者(A)可以包含后者(B)一个实例或者为null
  • HasRequired:前者必须包含后者一个不为null的实例
  • HasMany:前者包含后者实例的集合

2、With方法:

  • WithOptional:后者(B)可以包含前者(A)一个实例或者null
  • WithRequired:后者必须包含前者一个不为null的实例
  • WithMany:后者包含前者实例的集合

二、一对一关系:

两个类中先都要配置相应的引用属性

1、DataAnnotations数据标注的方式

用到ForeignKey外键标注。

public class Person
{
    public int PersonId { get; set; }
    public int SocialSecurityNumber { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [Timestamp]
    public byte[] RowVersion { get; set; }
    public PersonPhoto Photo { get; set; }
}

public class PersonPhoto
{
    [Key, ForeignKey("PhotoOf")] //注意:PersonPhoto表中的PersonId既是外键也必须是主键
    public int PersonId { get; set; }
    public byte[] Photo { get; set; }
    public string Caption { get; set; }
    public Person PhotoOf { get; set; }
}

2、Fluent API方式

(1)1:0..1关系

PersonPhoto必须属于一个Person,但是Person不一定有PersonPhoto, 此种情况下Person是一定存在的,所以它是主从关系主的一方。

modelBuilder.Entity<Person>().HasOptional(t => t.Photo).WithRequired(t => t.PhotoOf);
modelBuilder.Entity<PersonPhoto>().HasRequired(p => p.PhotoOf).WithOptional(p => p.Photo);

(2)1:1 关系

PersonPhoto必须属于一个Person,Person也必须有PersonPhoto。

modelBuilder.Entity<Person>().HasRequired(p => p.Photo ).WithRequiredPrincipal();
modelBuilder.Entity<PersonPhoto>().HasRequired(t => t.PhotoOf).WithRequiredDependent(t => t.Photo);

此种情况下,两个都一定存在,要确定主从关系,需要使用WithRequiredPrincipal或WithRequiredDependent。

  • 如果你选择 WithOptionalPrincipal(当前实体为主体;目标实体为依赖对象)PersonPhoto表中有一个外键,指向Person表的主键。
  • 如果你选择 WithOptionalDependen t则相反(当前实体为依赖对象;目标实体为主体)则代表Person表中有一个外键,指向PersonPhoto表的主键,

Person表可以没有对应的PersonPhoto表数据,但是PersonPhoto表每一条数据都必须对应一条Person表数据。意思就是人可以没有照片,但是有的照片必须属于某个人。

三、一对多关系:

1、DataAnnotations方式

一对多关系很多情况下我们都不需要特意的去配置,通过一些引用属性、导航属性等检测到模型之间的关系,自动为我们生成外键。

public class Destination
{//景点类
    public int DestinationId { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }
    public string Description { get; set; }
    public byte[] Photo { get; set; }
    public List Lodgings { get; set; }
}

public class Lodging
{//住宿类
    public int LodgingId { get; set; }
    public string Name { get; set; }
    public string Owner { get; set; }
    public bool IsResort { get; set; }
    public decimal MilesFromNearestAirport { get; set; }
    public Destination Target { get; set; }
}

Code First观察到Lodging类中有一个对Destination的引用属性,或者Destination中又有一个集合导航属性Lodgings,因此推测出Destination与Lodging的关系是一对多关系.

所以在生成的数据库中为自动为Lodging表生成外键:外键名:Target_DestinationId

2、更改外键的nullable属性和外键的名字

默认情况下,如果你的外键命名是规范的话,Code First自动会将该属性设置为外键,不再自动创建一个外键。 
规范命名是指符合:命名为如下的形式:(在这里目标类型就是Destination)

  • [目标类型的主键名]:如:DestinationId
  • [目标类型名称]+[目标类型主键名称]:如:DestinationDestinationId
  • [导航属性名称]+[目标类型主键名称]:如:TargetDestinationId

如:DestinationId属性自动作为主键。

public class Lodging
{
        public int? DestinationId { get; set; }
        public Destination Destination { get; set; }
}

当然我们也可以自己在类中增加一个外键。

1、使用Data Annotations指定外键:

注意ForeignKey位置的不同,其后带的参数也不同。

[ForeignKey("Target")]
public int TarDestinationId { get; set; }

public Destination Target { get; set; }

public int TarDestinationId { get; set; }

[ForeignKey("TarDestinationId")]
public Destination Target { get; set; }

2、用Fluent API指定外键:

如果实体类没定义AccommodationId,那么可以使用Map方法直接指定外键名:.Map(s => s.MapKey("AccommodationId")) 
(1)Lodging一定归属于一个Destination,这种关系是1:n。

modelBuilder.Entity<Destination>().HasMany(d => d.Lodgings).WithRequired(l => l.Destination).Map(l => l.MapKey("DestinationId"));
modelBuilder.Entity<Lodgings>().HasRequired(l => l.Target).WithMany(d=>d.Lodgings).HasForeignKey(l => l.TarDestinationId);

(2)Post可以单独存在,不用归属于Blog,这种关系是0..1:n。

modelBuilder.Entity<Destination>().HasMany(d => d.Lodgings).WithOptional(l => l.Destination).Map(l => l.MapKey("DestinationId"));
modelBuilder.Entity<Lodgings>().HasOptional(l => l.Target).WithMany(d => d.Lodgings).HasForeignKey(l => l.TarDestinationId);

3、对同一实体多个引用的情况

public class Person
{
    public int PersonID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List PrimaryContactFor { get; set; }
    public List SecondaryContactFor { get; set; }
}

public class Lodging
{
    public int LodgingId { get; set; }
    public string Name { get; set; }
    public string Owner { get; set; }
    public bool IsResort { get; set; }
    public decimal MilesFromNearestAirport { get; set; }
    public Destination Target { get; set; }
    //第一联系人
    public Person PrimaryContact { get; set; }
    //第二联系人
    public Person SecondaryContact { get; set; }
}

Lodging(旅店)有两个对Person表的引用,分别是PrimaryContact与SecondaryContact, 
同时,在Person表中也有对这两个联系人的导航:PrimaryContactFor与SecondaryContactFor。

因为在这两个表之间存在多个一对多关系,所以Code First无法处理这种情况。 
为了让Code First知道它们之间的对应关系,在这里要用到逆导航属性来解决。

(1)使用Data Annotations:

//第一联系人
[InverseProperty("PrimaryContactFor")]
public Person PrimaryContact { get; set; }
//第二联系人
[InverseProperty("SecondaryContactFor")]
Person SecondaryContact { get; set; }

(2)或使用Fluent API:

modelBuilder.Entity<Lodging>().HasOptional(l => l.PrimaryContact).WithMany(p => p.PrimaryContactFor);
modelBuilder.Entity<Lodging>().HasOptional(l=>l.SecondaryContact).WithMany(p=>p.SecondaryContactFor)).Map(p => p.MapKey("SecondaryPersonID "));;

在生成的数据库中为自动为Lodging表生成两个外键:PrimaryContact _PersonID 和SecondaryPersonID

4、级联删除

1、如果两个表之间存在一对多关系,Code First默认会开启两个表之间的级联删除功能 
数据库里可以可视化的设置不级联删除,Fluent API配置此外键关系时可以设置不级联删除:

this.HasMany(d => d.Lodgings).WithRequired(l => l.Destination).Map(l => l.MapKey("DestinationId")) //一对多并指定外键名
.WillCascadeOnDelete(false);   // 关闭级联删除

2、也可以在上下文的OnModelCreating方法中移除这个默认约定

modelBuilder.Conventions.Remove();

再需要开启级联删除,则可以在FluentAPI关系映射中用. WillCascadeOnDelete(true) 单独开启

四、多对多关系

如果有两个类中,各自都是导航属性指向另一个类,Code First会认为这两个类之间是多对多关系,例如:

public class Trip
{
    public int TripId { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public decimal CostUSD { get; set; }
    public byte[] RowVersion { get; set; }
    public List Activities { get; set; }
}

public class Activity
{
    public int ActivityId { get; set; }
    [Required, MaxLength(50)]
    public string Name { get; set; }
    public List Trips { get; set; }
}

Code First生成了一张中间表ActivityTrips,将另外两张表的主键都作为外键关联到了中间表上面。 
中间表中字段的命名默认为"[目标类型名称]_[目标类型键名称]".Activity_ActivityId 和Trip_TripId 
并且也作为这个新的连接表的联合主键。

指定表名

如果我们想指定中间表的名称和键名称,我们可以用Fluent API来配置。

modelBuilder.Entity<Trap>().HasMany(t => t.Activities).WithMany(a => a.Trips).Map(m =>
 {
     m.ToTable("TripActivities");
     m.MapLeftKey("TripIdentifier");//对应Trip的主键
     m.MapRightKey("ActivityId");
 });

 //或者
 modelBuilder<Activity>.Entity().HasMany(a => a.Trips).WithMany(t => t.Activities).Map(m =>
 {
     m.ToTable("TripActivities");
     m.MapLeftKey("ActivityId");//对应Activity的主键
     m.MapRightKey("TripIdentifier");
 });

到此这篇关于Entity Framework配置关系的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Entity Framework主从表数据加载方式

    一.延迟加载:LazyLoading 使用延迟加载,关联的实体必须标注为virtual. 本例是标注Destination类里的Lodgings为virtual.因为先发sql去查询主键对象,然后根据主键id去从表里查相关联的数据. private static void TestLazyLoading() { using (var context = new CodeFirst.DataAccess.BreakAwayContext()) { var canyon = (from d in c

  • Entity Framework代码优先(Code First)模式

    目录 一.Code First 代码优先 二.创建或生成Model代码 1.从数据库生成Model代码 2.手工创建Model代码 三.配置文件 四.操作 1.添加单个实体,Add 2.修改 3.删除,Remove 五.查询 1.Load(): 2.ToList(): 3.Find(): 4.Single().SingleOrDefault().First()等: 六.直接执行SQL语句 1.在实体上运行SQL命令, 2.在Database属性上运行SQL命令 一.Code First 代码优先

  • Entity Framework使用ObjectContext类

    目录 一.ObjectContext对象上下文 1.ObjectContext和DbContext的对比 2.ObjectContext类的实例封装的内容 3.类的结构: 二.实体对象查询:linq to Entities 1.AddObject :添加实体 2.DeleteObject: 删除实体 3.Detach: 分离实体 4.修改实体 5.保存到数据库 三.对象状态管理 1.ObjectStateEntry对象状态实体 2.ObjectStateManager对象状态管理器 五.Obje

  • Entity Framework模型优先与实体对象查询

    目录 一.概念: 1.EF6 可实现的功能: 二.安装Entity Framework6 1.VS2019 Installer安装“Entity Framework6 工具” 2.通过Nuget安装“Entity Framework”: 三.新建ObjectContext 和EntityObject 1.“根据模型生成的数据库”的设计器功能实现ModelFirst. 四.实体对象查询:linq to Entities 1.使用lambda表达式查询 2.执行存储过程(通过“添加”-----”函数

  • Entity Framework配置关系

    目录 一.Has方法与With方法 1.Has方法: 2.With方法: 二.一对一关系: 1.DataAnnotations数据标注的方式 2.Fluent API方式 (1)1:0..1关系 (2)1:1 关系 三.一对多关系: 1.DataAnnotations方式 2.更改外键的nullable属性和外键的名字 1.使用Data Annotations指定外键: 2.用Fluent API指定外键: 3.对同一实体多个引用的情况 4.级联删除 四.多对多关系 指定表名 一.Has方法与W

  • Entity Framework管理一对二实体关系

    在上一篇文章中,简单的介绍了使用Fluent API如何管理一对一的实体关系,在这篇文章中,接着介绍Fluent API如何管理一对多的实体关系. 要在数据库中配置一对多关系,我们可以依赖EF约定,还可以使用数据注解或Fluent API来显式创建关系.接下来使用捐赠者Donator和支付方法PayWay这两个类来举例子,这里的一对多关系是:一个人可以通过多种支付方式赞助我. 支付方式类PayWay结构如下: using System; using System.Collections.Gene

  • Entity Framework管理一对一实体关系

    我们现在已经知道如何使用Code First来定义简单的领域类,并且如何使用DbContext类来执行数据库操作.现在我们来看下数据库理论中的多样性关系,我们会使用Code First来实现下面的几种关系: 1.一对一关系: one to one 2.一对多关系: one to many 3.多对多关系::many to many 首先要明确关系的概念.关系就是定义两个或多个对象之间是如何关联的.它是由关系两端的多样性值识别的,比如,一对多意味着在关系的一端,只有一个实体,我们有时称为父母:在关

  • Entity Framework使用配置伙伴创建数据库

    在上一篇文章中讲了如何使用fluent API来创建数据表,不知道你有没有注意到一个问题.上面的OnModelCreating方法中,我们只配置了一个类Product,也许代码不是很多,但也不算很少,如果我们有1000个类怎么办?都写在这一个方法中肯定不好维护.EF提供了另一种方式来解决这个问题,那就是为每个实体类单独创建一个配置类.然后在OnModelCreating方法中调用这些配置伙伴类. 创建Product实体类: using System; using System.Collectio

  • Entity Framework使用Fluent API配置案例

    一.配置主键 要显式将某个属性设置为主键,可使用 HasKey 方法.在以下示例中,使用了 HasKey 方法对 Product 类型配置 ProductId 主键. 1.新加Product类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FluentAPI.Model { public cl

  • Entity Framework之DB First方式详解

    EF(Entity Framework的简称,下同)有三种方式,分别是:DataBase First. Model First和Code First. 下面是Db First的方式: 1. 数据库库中存在两个表,一个是专业表,一个学生表,一个学生只能属于一个专业: 其中T_Major是专业表,T_Student是学生表,StudentId是学号,MajorId是专业Id,T_Major与T_Student是一对多的关系. 2. 项目中添加数据库实体模型 因为之前没有配置过数据库连接,所以点击"新

  • c# 使用Entity Framework操作Access数据库的示例

    Entity Framework是C#开发中最常见的ORM工具.默认Entity Framework只提供支持MSSQL的provider factory.但是开发者开源贡献了对SQLite.MySql以及Access等的支持. Entity Framework将概念模型中定义的实体和关系映射到数据源,利用实体框架可以将数据源返回的数据具体化为对象:跟踪对象所做的更改:并发处理:将对象更改传播到数据源等.今天我们就一起讨论如何利用Entity Framework进行查询.插入.更新和删除数据.

  • Entity Framework Core关联删除

    目录 数据库关联删除行为 定义实体 Fluent API 配置关联实体 创建表结构 EF Core 关联实体删除行为 总结 DeleteBehavior.Cascade DeleteBehavior.SetNull DeleteBehavior.ClientSetNull DeleteBehavior.Restrict 关联删除通常是一个数据库术语,用于描述在删除行时允许自动触发删除关联行的特征:即当主表的数据行被删除时,自动将关联表中依赖的数据行进行删除,或者将外键更新为NULL或默认值. 数

  • Entity Framework Core延迟加载(懒加载)用法

    众所周知在EF 6 及以前的版本中,是支持懒加载(Lazy Loading)的,可惜在EF Core 并不支持,必须使用Include方法来支持导航属性的数据加载.不过现在EF Core的开发团队打算恢复对这一功能的支持(目前还未发布,不过可以在Github上面下载进行测试). 懒加载 懒加载也可以叫做按需加载.延迟加载.可以分两方面来理解,一方面指暂时不需要该数据,不用在当前马上加载,而可以推迟到使用它时再加载:另一方面指不确定是否将会需要该数据,所以暂时请不要加载,待确定需要后再加载它.懒加

  • Entity Framework加载控制Loading Entities

    Entity Framework允许控制对象之间的关系,在使用EF的过程中,很多时候我们会进行查询的操作,当我们进行查询的时候,哪些数据会被加载到内存中呢?所有的数据都需要吗?在一些场合可能有意义,例如:当查询的实体仅仅拥有一个相关的子实体时可以加载所有的数据到内存中.但是,在多数情况下,你可能并不需要加载全部的数据, 而是只要加载一部分的数据即可. 默认情况下,EF仅仅加载查询中涉及到的实体,但是它支持两种特性来帮助你控制加载: 1.贪婪加载 2.延迟加载 下面以客户类型.客户和客户邮件三个实

随机推荐