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


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


规范命名是指符合:命名为“[目标类型的键名],[目标类型名称]+[目标类型键名称]”,或“[导航属性名称]+[目标类型键名称]”的形式,在这里目标类型就是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);
对同一个实体多个引用的情况
我们来考虑一下下面的情况:
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; }
}


使用Fluent API:
modelBuilder.Entity<PersonPhoto>().HasRequired(p => p.PhotoOf).WithOptional(p => p.Photo);
注意:PersonPhoto表中的PersonId既是外键也必须是主键
来源:https://www.cnblogs.com/liangxiaofeng/p/5809451.html
EF Code First 导航属性 与外键(转载)的更多相关文章
- EF Code First 导航属性 与外键
一对多关系 项目中最常用到的就是一对多关系了.Code First对一对多关系也有着很好的支持.很多情况下我们都不需要特意的去配置,Code First就能通过一些引用属性.导航属性等检测到模型之间的 ...
- EF Code First中的主外键约定和一对一、一对多关系的实现
对于主外键约定的理解,其实是学习实体间一对一和一对多关系的基础. 1.1 主键(Key)约定 主键的默认约定是:只要字段名为--实体名(类名)+"id"(不区分大小写),这就算是默 ...
- EF Code First导航属性一对一关系中注意点及配置方法
//学生 public class Student { [key] public int StId { get; set; } public int SocialSecurityNumber { ge ...
- ASP.NET EF 延迟加载,导航属性延迟加载
ASP.NET EF 延迟加载,导航属性延迟加载 EF(EntityFramework)原理:属于ORM的一种实现 通过edmx文件来查看三部分:概念模型,数据模型,映射关系,上下文DbConte ...
- EF Core反向导航属性解决多对一关系
多对一是一种很常见的关系,例如:一个班级有一个学生集合属性,同时,班级有班长.语文课代表.数学课代表等单个学生属性,如果定义2个实体类,班级SchoolClass和学生Student,那么,班级Sch ...
- EF架构~过滤导航属性等,拼接SQL字符串
拼接T-SQL串,并使它具有通用性 好处:与服务器建立一次连接,给服务器发一条SQL命令,即可实现 代码如下: 1 /// <summary> 2 /// 构建Insert语句串 3 // ...
- EF架构~为导航属性赋值时ToList()的替换方案
回到目录 今天在进行EF开发时,遇到一个问题,在进行join查询时,类中的一个集合类型的导航属性,在给它赋值时,将查询出来的结果ToList()后,出错了,linq to entity不支持这种操作, ...
- ASP.NET Core EF 查询获取导航属性值,使用Include封装
// 引用 using Microsoft.EntityFrameworkCore; // 摘要: // Specifies related entities to include in the qu ...
- mvc EF框架中,加载外键对象序列化对象时报错 序列化类型为XX的对象时检测到循环引用
Newtonsoft.Json.dll 或者通过->工具->库程序包管理工具->NuGet管理包->联机 输入Newtonsoft或者json.net Newtonsoft.J ...
随机推荐
- uc/osⅡ/Ⅲ
1.关于任务堆栈时#if在main()中的用法: #if ... #else#endif//与#if对应作为一个编译“开关”,比如#if(条件满足) 执行代码1 #else 执行代码2 #endif ...
- webapi使用swagger出现“Cannot read property 'parameters' of null”
前端时间在webapi项目使用swagger来提供接口文档及测试工具,按网上方法(http://wmpratt.com/swagger-and-asp-net-web-api-part-1)配置好之后 ...
- OO第一次博客总结
虽然早在开学之前就已耳闻过OO这门课的威力,也在寒假自学了一些java的语法,但在真正面对OO这样的工程训练时才发现寒假所学的那点语法简直不值一提,也深刻的感受到在这个过程中自己的提升确实很快,毕竟d ...
- 包建强的培训课程(14):Android与ReactNative
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- python爬虫学习之XPath基本语法
XPath 使用路径表达式来选取 XML 文档中的节点或节点集.节点是通过沿着路径(path)或者步(steps)来选取的. XML实例文档 我们将在下面的例子中使用这个XML文档. <?xml ...
- #Java学习之路——基础阶段(第二篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- 【Spark调优】聚合操作数据倾斜解决方案
[使用场景] 对RDD执行reduceByKey等聚合类shuffle算子或者在Spark SQL中使用group by语句进行分组聚合时,经过sample或日志.界面定位,发生了数据倾斜. [解决方 ...
- ubuntu双网卡配置,实现内网外网同时访问!
我们假定内网IP为:10.35.0.58,内网网关为:10.35.0.254:外网IP为222.76.250.4,外网网关为:222.76.250.1.其中局域名网需要连接:10.35.0.X,10. ...
- springBoot(8)---整合redis
Springboot整合redis 步骤讲解 1.第一步jar导入: <dependency> <groupId>org.springframework.boot</gr ...
- HDU 1006 Tick and Tick 时钟指针问题
Tick and Tick Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...