Entity Framework配置关系

作者:springsnow 时间:2023-10-15 09:45:30 

一、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");
});

来源:https://www.cnblogs.com/springsnow/p/13230085.html

标签:Entity,Framework,配置,关系
0
投稿

猜你喜欢

  • Android的RV列表刷新详解Payload与Diff方式异同

    2023-07-05 13:17:29
  • java程序员如何编写更好的单元测试的7个技巧

    2023-09-05 14:57:24
  • 为什么wait和notify必须放在synchronized中使用

    2022-07-20 07:32:39
  • C#实现合并多张图片为GIF动态图

    2022-12-13 04:16:35
  • 使用MyBatisPlus自动生成代码后tomcat运行报错的问题及解决方法

    2022-02-23 05:24:55
  • C#动态执行批处理命令的方法

    2023-03-16 23:19:40
  • IntelliJ IDEA2022.3 springboot 热部署含静态文件(最新推荐)

    2023-07-07 10:41:58
  • Spring Boot + Mybatis-Plus实现多数据源的方法

    2023-11-13 15:01:46
  • Spring中XML schema扩展机制的深入讲解

    2022-06-29 07:44:15
  • Android仿微信Viewpager-Fragment惰性加载(lazy-loading)

    2023-12-16 23:50:59
  • 基于springboot 长轮询的实现操作

    2022-02-06 09:46:22
  • C#使用log4net记录日志的方法步骤

    2021-07-07 18:14:55
  • C# 设置防火墙的创建规则

    2023-03-21 09:13:42
  • android Watchdog 实现剖析

    2022-07-12 06:39:21
  • 使用SpringBoot实现微服务超时重试模式的示例

    2021-12-28 13:58:45
  • Java中String、StringBuffer、StringBuilder的区别详解

    2023-03-28 00:06:50
  • 100-200之间所有素数求和程序代码(二个版本)

    2022-07-03 18:53:58
  • Java try catch finally异常处理组合详解

    2021-07-04 18:19:51
  • Java实现DFA算法对敏感词、广告词过滤功能示例

    2023-02-11 10:24:33
  • Java花式解决'分割回文串 ii'问题详解

    2022-07-09 02:01:58
  • asp之家 软件编程 m.aspxhome.com