Entity Framework 一对一关系映射
一对一关系是Entity Framework 中很复杂的关系,涉及了 HasOptional 、WithRequired 、 WithOptionalPrincipal 、 WithOptionalDependent。这篇文章我们将具体讲解这几个的用法。
我们以会员和订单为例,一个会员有可能有订单,也可能没有订单,但是一个订单绝对属于一个会员。我们先编写出会员和订单的类代码:
public class Member
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Order Order { get; set; }
}
public class Order
{
public int Id { get; set; }
public int Name { get; set; }
public int Num { get; set; }
public virtual Member Member { get; set; }
}
零、 HasOptionl then WithRequired
这种方式的会员和订单的映射类如下:
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
ToTable("Member");
HasKey(p => p.Id);
Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasOptional(p => p.Order).WithRequired(p => p.Member);
}
}
public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
ToTable("Order");
HasKey(p => p.Id);
Property(p => p.Id).HasColumnName("MemberId")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
这里将 Member 类的Id设为自增长,将 Order 的Id设置别名 MemberId 且非自增长。编写晚上下文类和调用类后,运行代码后,我们在数据库中将看到如下图:
其中 MemberId 就是在 OrderMap 中设置的别名
一、 HasOptionl then WithOptionalPrincipal
现在我们修改一下 MemberMap 和 OrderMap ,将 Member 和 Order 的Id都设置成自增长。
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
ToTable("Member");
HasKey(p => p.Id);
Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasOptional(p => p.Order).WithOptionalPrincipal(p => p.Member);
}
}
public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
ToTable("Order");
HasKey(p => p.Id);
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
再次执行代码后,查看生成的数据库:
我们看到 Order 表中 Member_Id 字段是EF自动生成的外键,且不可为空
二、 HasOptionl then WithOptionalDependent
再次修改 MemberMap 和 OrderMap :
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
ToTable("Member");
HasKey(p => p.Id);
Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasOptional(p => p.Order).WithOptionalDependent(p => p.Member);
}
}
public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
ToTable("Order");
HasKey(p => p.Id);
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
保存代码,运行程序,查看数据库:
和上一小节生成的数据库相比,这一小节生成的数据库 Member 表中自动生成了 Order 表的外键 Order_Id ,而 Order 表没有生成任何外键。
注:使用 WithOptionalPrincipal 可以使实体作为主体,将包含关系主键。使用 WithOptionalDependent 可以使实体作为以来提,将包含关系的外键。
前面所讲的都是从 Member 入手,我们同样也可以从 Order 表入手,但是在实际开发中我不建议这么做。下面就来说一下从 Order 入手的方法。
三、 HasRequired then WithOptional
同样我们修改 MemberMap 和 OrderMap :
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
ToTable("Member");
HasKey(p => p.Id);
Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public OrderMap()
{
ToTable("Order");
HasKey(p => p.Id);
Property(p => p.Id).HasColumnName("MemberId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasRequired(p => p.Member).WithOptional(p => p.Order);
}
这种方法生成的数据库与第一种方法结果一样。
四、 HasRequired 和 WithOptional
我们最后一次修改 MemberMap 和 OrderMap :
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
ToTable("Member");
HasKey(p => p.Id);
Property(p => p.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
ToTable("Order");
HasKey(p => p.Id);
Property(p => p.Id).HasColumnName("MemberId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasRequired(p => p.Member).WithOptional(p => p.Order).Map(p => p.MapKey("Member_Id")))
}
}
这种方法生成的数据库与第二种方法结果一样。
- 设计模式学习--面向对象的5条设计原则之Liskov替换原则--LSP
- 生信主管应该了解的十个Linux知识点
- 数据库结构版本控制
- 分布式计划任务设计与实现
- 设计模式学习--面向对象的5条设计原则之开放封闭原则--OCP
- 网络测试,带宽测试,流量测试
- github极简指南
- 设计模式学习--面向对象的5条设计原则之单一职责原则--SRP
- Spring RestFul Example (实例参考)
- C#基础知识回顾---你不知道的Lazy<T>
- 用python编写验证码
- WPF备忘录(6)WPF实现打印功能
- 适合开发者的深度学习:第一天就能使用的编码神经网络工具
- Shell 历史记录异地留痕审计与监控
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PythonforResearch | 0_语法基础
- iOS 系统中的视图动画
- 在 Android 的 /data 目录下添加虚拟内存
- 玩转安卓模拟器命令行
- 如何利用NLog输出结构化日志,并在Kibana优雅分析日志?
- Android 应用保存状态
- 2020-8-9日报:修复zip在某些X64机器上的运行崩溃问题
- 专题一:预处理数据(使用sklearn-preprocessing)
- 「Docker」使用 Docker run 覆盖 ENTRYPOINT
- 尝试在 Mono 3.0 下运行 ASP.NET MVC 4
- CentOS7使用yum安装nginx报错:获取 GPG 密钥失败:[Errno 14] curl#60 - "Peer's Certificate has expired."
- iOS 应用使用位置信息
- Silverlight CreateObjectEx 参考
- NHibernate 配置使用 Formula
- Not allowed to navigate top frame to data URL问题