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
猜你喜欢
- 最近在做一个搜索相关的项目,需要爬取网络上的一些链接存储到索引库中,虽然有很多开源的强大的爬虫框架,但本着学习的态度,自己写了一个简单的网络
- 本文实例讲述了Java模拟死锁发生之演绎哲学家进餐问题。分享给大家供大家参考,具体如下:一 点睛常见的死锁形式:当线程1已经占据资源R1,并
- 目录介绍需求来源传统算法问题新算法特点性能数据效果“我”是什么适用范围能用多久★★集成建议★★常规集成大型分布式集成配置变更代码示例运行环境
- 最近学习Spring的源码,发现一个利器BeanPostProcessor。这个后置处理器可以在bean初始化前后对bean进行操作。我们可
- 在Spring中进行事务管理非常简单,只需要在方法上加上注解@Transactional,Spring就可以自动帮我们进行事务的开启、提交、
- 本文实例讲述了C#读取系统字体颜色与大小的方法。分享给大家供大家参考。具体分析如下:首先,说到字体、颜色,我们应该想到System.Draw
- 一个系统上线,肯定会或多或少的存在异常情况。为了更快更好的排雷,记录请求参数和响应结果是非常必要的。所以,Nginx 和 Tomcat 之类
- 前言研究表明,Java堆中对象占据最大比重的就是字符串对象,所以弄清楚字符串知识很重要,本文主要重点聊聊字符串常量池。Java中的字符串常量
- 文章来源:互联网 作者:ggg82/CSDN现在许多用户界面都使用工具栏制作菜单条,小弟最近对此感兴趣,便从网上求助,可是得到的帮助大多是B
- 前言:学习了SpringBoot分页查询的两种写法,一种是手动实现,另一种是使用框架实现。现在我将具体的实现流程分享一下。首先是手动实现分页
- 在很多项目中,为了安全安全考虑,需要对数据包进行加密处理,本文实例所述的即为C#加密代码,在应用开发中有很大的实用价值。说起数据包加密,其实
- 前言前面一篇我们介绍了使用 shared_preferences实现简单的键值对存储,然而我们还会面临更为复杂的本地存储。比如资讯类 App
- 下面是一个AOP实现的简单例子:首先定义一些业务方法:/** * Created with IntelliJ IDEA. 
- 本文实例为大家分享了java实现省市区转换成树形结构的具体代码,供大家参考,具体内容如下前言:为什我想写这篇博客呢?第一方面是记录,另一方面
- 一、什么是CharacterEncodingFilter官方解释如下是spring内置过滤器的一种,用来指定请求或者响应的编码格式。在web
- 前言上文讲的MyBatis部署运行且根据官网运行了一个demo:一步到位部署运行MyBatis3源码<保姆级>jdbc再贴一个J
- 一.瀑布模型瀑布模型严格遵循软件生命周期各阶段的固定顺序:计划、分析、设计、编程、训试和维护,上一阶段完成后才能进入到下一阶段, 整个模型就
- 1.什么是mybatis动态sql看到动态,我们就应该想到,这是一个可以变化的sql语句MyBatis的动态SQL是基于OGNL表达式的,它
- 1.Java连接redisredis支持哪些语言可以操作 (去redis官网查询)1.1 使用Jedis (1)添加jedis依赖
- 前言我们来分析一下堆内布局以及Java对象在内存中的布局吧。对象的指向先来看一段代码:package com.zwx.jvm;public