EF Code First 学习笔记:关系(转)
一对多关系
项目中最常用到的就是一对多关系了。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
EF Code First 学习笔记:关系(转)的更多相关文章
- EF Code First 学习笔记:关系
一对多关系 项目中最常用到的就是一对多关系了.Code First对一对多关系也有着很好的支持.很多情况下我们都不需要特意的去配置,Code First就能通过一些引用属性.导航属性等检测到模型之 ...
- EF Code First学习笔记
EF Code First学习笔记 初识Code First EF Code First 学习笔记:约定配置 Entity Framework 复杂类型 Entity Framework 数据生成选项 ...
- EF Code First 学习笔记:表映射
多个实体映射到一张表 Code First允许将多个实体映射到同一张表上,实体必须遵循如下规则: 实体必须是一对一关系 实体必须共享一个公共键 观察下面两个实体: public class Perso ...
- EF Code First学习笔记 初识Code First
Code First是Entity Framework提供的一种新的编程模型.通过Code First我们可以在还没有建立数据库的情况下就开始编码,然后通过代码来生成数据库. 下面通过一个简单的示例来 ...
- EF Code First学习笔记 初识Code First(转)
Code First是Entity Framework提供的一种新的编程模型.通过Code First我们可以在还没有建立数据库的情况下就开始编码,然后通过代码来生成数据库. 下面通过一个简单的示例来 ...
- EF Code First 学习笔记:表映射 多个Entity到一张表和一个Entity到多张表
多个实体映射到一张表 Code First允许将多个实体映射到同一张表上,实体必须遵循如下规则: 实体必须是一对一关系 实体必须共享一个公共键 观察下面两个实体: public class Per ...
- EF Code First 学习笔记:表映射(转)
多个实体映射到一张表 Code First允许将多个实体映射到同一张表上,实体必须遵循如下规则: 实体必须是一对一关系 实体必须共享一个公共键 观察下面两个实体: public class Per ...
- EF Code First 学习笔记:约定配置 Data Annotations+Fluent API
要更改EF中的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面;还有一个就 ...
- [转载]EF Code First 学习笔记:约定配置
要更改EF中的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面;还有一个就 ...
随机推荐
- 第十六篇:初探IO复用
前言 在之前的文章中,我具体实现了一个并发回射服务器并给它加载了僵尸子进程的自动清理信号机制.在正常情况下,它已经可以很好地工作了,但它能否合理应对一些特殊情况呢? 问题发现 先来看看当服务器的客户子 ...
- 佛祖保佑永无bug
世界最难懂C语言代码竞赛: // _ooOoo_ // o8888888o // 88" . "88 // (| -_- |) // O\ = /O // ____/`---'\_ ...
- cocos2d-x游戏引擎核心之十二——3.x新特性
v3.0 亮点 使用 C++(C++11) 的特性取代了 Objective-C 的特性 优化了 Labels 优化了渲染器(比 v2.2 更快) 新的事件分发机制 物理引擎集成 新的 UI 对象 J ...
- 元素设置disabled属性后便无法向后台传值
元素设置disabled属性后便无法向后台传值
- iOS - 布局重绘机制相关方法的研究
iOS View布局重绘机制相关方法 布局 - (void)layoutSubviews - (void)layoutIfNeeded- (void)setNeedsLayout —————————— ...
- Gamma编码及Delta编码概述
一.Elias Gamma Coding 即Gamma编码,是一种对正整数进行编码的统一编码,由Peter Elias发明.适用于预先无法获知最大编码整数的情况,而且小整数出现频率高,大整数出现频率低 ...
- Jquery跨域Ajax取值
HTML: $.ajax({ type: "get", async: false, url: "http://www.xxxxxx.com/otherLogin/chec ...
- 《转》python学习(7) -列表
转自 http://www.cnblogs.com/BeginMan/p/3153842.html 一.序列类型操作符 1.切片[]和[:] 2.成员关系操作符(in ,not in ) 1: s1 ...
- 报错 ERROR in static/js/vendor.b3f56e9e0cd56988d890.js from UglifyJs
开发vux项目在引入 // 表单验证组件-start import zh_CN from 'vee-validate/dist/locale/zh_CN' import Validator from ...
- centos7上开启单用户模式
author: headsen chen date : 2018-08-02 11:23:16 1,在出现centos7的页面的时候,按 e进入到编译内核的界面 2,找到下面的这一段,将ro 该车 ...