一对多关系

项目中最常用到的就是一对多关系了。Code First对一对多关系也有着很好的支持。很多情况下我们都不需要特意的去配置,Code First就能通过一些引用属性、导航属性等检测到模型之间的关系,自动为我们生成外键。观察下面的类:

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<Lodging> 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 Destination { get; set; }}
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<Lodging> 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 Destination { get; set; }}

Code First观察到Lodging类中有一个对Destination的引用属性,同时Destination中又有一个集合导航属性Lodgings,因此推测出Destination与Lodging的关系是一对多关系,所以在生成的数据库中为自动为Lodging表生成外键:

其实,只要在一个类中存在引用属性,即:

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 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 Destination { get; set; }} 
 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 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 Destination { get; set; }} 

或一另一个类中存在导航属性:

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<Lodging> 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 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<Lodging> 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; }} 

Code First都能检测到它们之间一对多的关系,自动生成外键。

 指定外键

当然我们也可以自己在类中增加一个外键。默认情况下,如果你的外键命名是规范的话,Code First会将的该属性设置为外键,不再自动创建一个外键,如:

 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<Lodging> 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 int TargetDestinationId { get; set; }public Destination Target { get; set; }} 
 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<Lodging> 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 int TargetDestinationId { get; set; }public Destination Target { get; set; }} 

规范命名是指符合:命名为“[目标类型的键名],[目标类型名称]+[目标类型键名称]”,或“[导航属性名称]+[目标类型键名称]”的形式,在这里目标类型就是Destination,相对应的命名就是:DestinationId,DestinationDestinationId,TargetDestinationId

对于命名不规范的列,Code First会怎做呢?

比如我们将外键改为:

public int TarDestinationId { get; set; }

再重新生成数据库:

可以看到Code First没有识别到TarDestinationId是一个外键,于是自己创建了一个外键:Target_DestinationId。这时我们要告诉Code First该属性是一个外键。

使用Data Annotations指定外键:

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

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

注意ForeignKey位置的不同,其后带的参数也不同。这样,生成的数据库就是我们所期望的了。Code First没有再生成别的外键。

用Fluent API指定外键:

modelBuilder.Entity<Lodging>().HasRequired(p => p.Target).WithMany(l => l.Lodgings).HasForeignKey(p => p.TarDestinationId);

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

我们来考虑一下下面的情况:

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; } } public class Person{public int PersonID { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public List<Lodging> PrimaryContactFor { get; set; }public List<Lodging> SecondaryContactFor { get; set; } }

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

看看Code First默认会生成怎样的数据库

天哪,竟然生成了四个外键。因为有两套类型一样的导航属性与引用属性,Code First无法确定它们之间的对应关系,就单独为每个属性都创建了一个关系。这肯定不是我们所期望的,为了让Code First知道它们之间的对应关系,在这里要用到逆导航属性来解决。

使用Data Annotations:

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

或使用Fluent API:

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

再重新生成数据库,结果如图:

多对多关系

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

 public class Activity{public int ActivityId { get; set; }[Required, MaxLength(50)] public string Name { get; set; } public List<Trip> Trips { get; set; }}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<Activity> Activities { get; set; }}

一个Trip类可以有一些Activites日程,而一个Activity日程又可以计划好几个trips(行程),显然它们之间是多对多的关系。我们看看默认生成的数据库是怎么样的:

可以看到,Code First生成了一张中间表ActivityTrips,将另外两张表的主键都作为外键关联到了中间表上面。中间表中键的命名默认为"[目标类型名称]_[目标类型键名称]".

指定表名

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

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

或:

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

一对一关系

如果我们要将两个类配置为一对一关系,则两个类中都要配置相应的引用属性,如:

 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]public int PersonId { get; set; }public byte[] Photo { get; set; }public string Caption { get; set; }public Person PhotoOf { get; set; }}

我们为一个(Person)对应着一张相片(PersonPhoto),但如果根据这样的模型生成数据库为报错:

无法确定类型“BreakAway.PersonPhoto”与“BreakAway.Person”之间的关联的主体端。必须使用关系 Fluent API 或数据注释显式配置此关联的主体端

因为Code First无法确认哪个是依赖类,必须使用Fluent API或Data Annotations进行显示配置。

使用Data Annotations

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")]public int PersonId { get; set; }public byte[] Photo { get; set; }public string Caption { get; set; }public Person PhotoOf { get; set; }}
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")]public int PersonId { get; set; }public byte[] Photo { get; set; }public string Caption { get; set; }public Person PhotoOf { get; set; }}

使用Fluent API:

modelBuilder.Entity<PersonPhoto>().HasRequired(p => p.PhotoOf).WithOptional(p => p.Photo);

注意:PersonPhoto表中的PersonId既是外键也必须是主键

转自:http://www.cnblogs.com/Gyoung/archive/2013/01/22/2869782.html

转载于:https://www.cnblogs.com/ITGirl00/p/3533393.html

EF Code First 学习笔记:关系(转)相关推荐

  1. EF Code First 学习笔记:关系

    一对多关系 项目中最常用到的就是一对多关系了.Code First对一对多关系也有着很好的支持.很多情况下我们都不需要特意的去配置,Code First就能通过一些引用属性.导航属性等检测到模型之间的 ...

  2. EF Code First学习笔记:数据库创建(转)

    控制数据库的位置 默认情况下,数据库是创建在localhost\SQLEXPRESS服务器上,并且默认的数据库名为命名空间+context类名,例如我们前面的BreakAway.BreakAwayCo ...

  3. EF Code First 学习笔记:约定配置

    要更改EF中的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面;还有一个就 ...

  4. iOS Code Signing 学习笔记转写

    最近看了objc.io上第17期中的文章 <Inside Code Signing> 对应的中文翻译版 <代码签名探析> ,受益颇深,对iOS代码签名机制有了进一步的认识.想了 ...

  5. 《The Art of Readable Code》学习笔记(一)

    放寒假回家有些颓废,就是不想看书.但是已经大三了,春节过后就要找实习了.哎,快乐的大学生活终于要过去了. 先从简单的书看起吧!在图书馆借了本<The Art of Readable Code&g ...

  6. 数据库概论学习笔记——关系数据理论

    属性间的联系 1.一对一联系 2.一对多联系 3.多对多联系 数据依赖 是一个关系内部属性与属性之间的一种约束关系 是现实世界属性间相互联系的抽象 是数据内在的性质 是语义的体现 1.函数依赖 2.多 ...

  7. 《代码整洁之道 clean code》学习笔记

    文章目录 0 前言 1 注释 C1:不恰当的信息 C2:废弃的注释 C3:冗余的注释 C4:糟糕的注释 C5:注释掉的代码 2 环境 E1:需要多步才能实现的构建 E2:需要多步才能做到的测试 3 函 ...

  8. PostgreSQL学习笔记(更新ing)+c# 使用ef连接数据库postgreSQL

    目录 PostgreSQL学习笔记 一.PostgreSQL创建.删除数据库(表).架构 1.创建数据库 CREATE DATABASE 2.查看数据库 3.删除数据库 4.创建表 5.删除表 6.架 ...

  9. amazeui学习笔记--css(HTML元素2)--代码Code

    amazeui学习笔记--css(HTML元素2)--代码Code 一.总结 1.行内代码:code标签<code> 2.代码片段:pre标签<pre> 3.限制代码块高度:添 ...

最新文章

  1. Input type=“file“上传文件change事件只触发一次解决方案
  2. MongoDB源码概述——使用日志提升单机数据可靠性
  3. HyperLedger Fabric 错误记录
  4. mysql SQLyog导入导出csv文件
  5. limit mongodb 聚合_MongoDB 统计 group 操作用不了,试试 mapReduce 吧
  6. python-循环-打印菱形图案
  7. 基于移动最小二乘的图像变形
  8. 计算机在食品科学中的应用统计学,响应面法及其在食品中的应用
  9. 翻译学习 | 混合线性模型的思考
  10. 【echarts应用】---pie饼图篇
  11. sklearn专题六:聚类算法K-Means
  12. 鸟什么羊什么的成语(鸟什么羊什么四字成语大全)
  13. Java线程状态转化
  14. 服务器事件查看器根据登录id如何查找信息,Windows中如何查看日志(如查看远程登陆的IP地址)以及常用日志ID...
  15. 万字长文:2019 年 京东 PLUS 会员前端重构之路
  16. win10如何修改锁屏(欢迎界面)的用户名
  17. PHP错题本功能实现,收藏| 最高效的"错题本"制作攻略!手把手教会你!
  18. 手撸一款Android屏幕适配SDK
  19. 游戏 | python打包游戏为exe可执行文件
  20. Catia V5R21软件安装教程

热门文章

  1. python汽车行驶工况_什么叫车辆行驶工况
  2. oracle安装必要的,CentOSOracle安装必要的软件创建数据库
  3. python爬虫用多线程还是多进程_python爬虫之多线程、多进程爬虫
  4. cassandra本地连接失败_无法连接到本地Cassandra实例?
  5. python学习-类(global、nonlocal、继承、多态)
  6. 中班游戏电子计算机,幼儿园中班数学游戏:小小快递员
  7. fft重叠帧_关于FFT实时频谱的几个基本概念 | 科创仪表局
  8. win10无法查看计算机名,win10如何查看计算机名字
  9. python3读取网页_python3+selenium获取页面加载的所有静态资源文件链接操作
  10. 研究所月入两万,是一种什么体验?