博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
EF Code First 学习笔记:关系
阅读量:5794 次
发布时间:2019-06-18

本文共 8235 字,大约阅读时间需要 27 分钟。

一对多关系

项目中最常用到的就是一对多关系了。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
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 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; } }

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
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
().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
PrimaryContactFor { get; set; } public List
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
().HasOptional(l => l.PrimaryContact).WithMany(p => p.PrimaryContactFor); modelBuilder.Entity
().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
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
Activities { get; set; } }

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

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

指定表名

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

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

或:

modelBuilder.Entity
().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; }    }

使用Fluent API:

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

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

 

如果我的文章对你有帮助,就点一下推荐吧.(*^__^*)

转载地址:http://aqffx.baihongyu.com/

你可能感兴趣的文章
CSS Custom Properties 自定义属性
查看>>
vim
查看>>
MVVM计算器(下)
查看>>
C++中指针和引用的区别
查看>>
簡單分稀 iptables 記錄 udp 微軟 138 端口
查看>>
Java重写equals方法和hashCode方法
查看>>
Spark API编程动手实战-07-join操作深入实战
查看>>
H3C-路由策略
查看>>
centos 修改字符界面分辨率
查看>>
LNMP之Mysql主从复制(四)
查看>>
JS二维数组的声明和使用
查看>>
v$archive_gap dg dataguard 断档处理 scn恢复
查看>>
问责IT风险管理:CIO需关注两个重点
查看>>
Winform打包发布图解
查看>>
PDF文件怎么编辑,超简单的方法
查看>>
EasyUI基础入门之Easyloader(载入器)
查看>>
Uva 839 Not so Mobile
查看>>
30款超酷的HTTP 404页面未找到错误设计
查看>>
程序猿必备 MyEclipse2013-2014系列
查看>>
java中ArrayList 、LinkList区别
查看>>