Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表。然而,有时候,不能也不想遵循这些约定,那就需要重写它们。重写默认约定有两种方式:Data Annotations和FluentAPI。Data Annotations在功能上是Fluent API的子集,在一些映射场景下使用Annotations不能达到重写的目的,因此本篇文章中使用Fluent API配置属性。

一、Fluent API配置属性

Code First Fluent API通常情况下是在DbContext的派生类中重写OnModelCreating方法。

1.配置Length

Length用来描述数组的长度,当前包括string和Byte数组。

默认约定:Code First对string或byte数组的默认长度约定是max。注意:Sql Server Compact中默认最大数组长度是4000。

重写约定:使用HasMaxLength(nn),参数为可空整数。

  1. 1: Property(t => t.Name).HasMaxLength(50);

另外关于Length的Fluent API还有下面2个:

IsFixedLength(),配置属性为固定长度。

IsMaxLength(),配置属性为数据库提供程序允许的最大长度。

2.配置Data Type

Data Type表示将.NET类型映射到的数据库的数据类型。

默认约定:列的数据类型由使用的数据库提供程序决定。以SQL Server为例:String->nvarchar(max),Integer->int,Byte[]->varbinary(max),Boolean->bit。

重写约定:使用HasColumnType(“xxx”),下面列子的Photo是byte[]类型,配置映射到image数据类型:

  1. 1: Property(t => t.Photo).HasColumnType("image");

3.配置允许为空和不允许为空

默认约定:主键属性不允许为空,引用类型(String,array)允许为空,值类型(所有的数字类型,Datetime,bool,char)不允许为空,可空的值类型Nullable<T>允许为空。

重写约定:使用IsRequired()配置不允许为空,使用IsOptional()配置允许为空。下面配置Name属性为不为空:

  1. 1: Property(t => t.Name).IsRequired();

4.配置属性到指定列

默认约定:映射到与属性名相同的列。

重写约定:使用Property(t=>t.属性名).HasColumnName(“xxx”)。下面配置Name映射到DepartmentName:

  1. 1: Property(t => t.Name).HasColumnName("DepartmentName");

5.配置主键

默认约定:(1)属性名为ID或Id的默认为主键

(2)类名+ID或类名+Id默认为主键  (其中ID或Id的优先级大于类名+ID或类名+Id)

重写约定:使用HasKey(t=>t.属性名)。下面将BlogId配置为主键:

  1. 1: HasKey(t => t.BlogId);

6.配置组合主键

下面的例子将DepartmentId和Name属性组合作为Department类型的主键:

  1. 1: HasKey(t => new { t.DepartmentId, t.Name });

7.配置Database-Generated

默认约定:整型键:Identity。

重写约定:使用Property(t => t.属性名).HasDatabaseGeneratedOption(DatabaseGeneratedOption)。

DatabaseGeneratedOption枚举包括三个成员:

(1) None:数据库不生成值

(2) Identity:当插入行时,数据库生成值

(3) Computed:当插入或更新行时,数据库生成值

整型默认是Identity,数据库生成值,自动增长,如果不想数据库自动生成值,使用DatabaseGeneratedOption.None。

Guid类型作为主键时,要显示配置为DatabaseGeneratedOption.Identity。

8.配置TimeStamp/RowVersion的乐观并发

默认约定:这个没有默认约定。

配      置:使用Property(t=>t.属性名).IsRowVersion()

  1. 1: Property(t => t.RowVersion).IsRowVersion();

9.不配置TimeStamp的乐观并发

有些数据库不支持RowVersion类型,但是又想对数据库的一个或多个字段并发检查,这时可以使用Property(t=>t.属性名).IsConcurrencyToken(),下面的例子将SocialSecurityNumber配置为并发检查。

  1. 1: Property(t => t.SocialSecurityNumber).IsConcurrencyToken();

10.配置String属性是否支持Unicode内容

默认约定:默认string是Unicode(在SQL Server中是nvarchar)的。

重写约定:下面的例子使用IsUnicode()方法将Name属性配置为varchar类型的。

  1. 1: Property(t => t.Name).IsUnicode(false);

11.配置小数的精度和小数位数

默认约定:小数是(18,2)

配      置:使用Property(t=>t.属性名).HasPrecision(n,n)

  1. 1: public decimal MilesFromNearestAirport { get; set; }

12.复杂类型

默认复杂类型有以下规则:

(1) 复杂类型没有主键属性 
(2) 复杂类型只能包含原始属性。 
(3)在其他类中使用复杂类型时,必须表示为非集合类型。

使用DbModelBuilder.ComplexType方法显示配置为复杂类型:

  1. 1: modelBuilder.ComplexType<Address>();

13.嵌套的复杂类型

嵌套的复杂类型只需显示配置外层,内层自动继承复杂类型的约定。

14.配置复杂类型的属性

配置复杂类型的属性和配置实体属性一样,具体参考下面的实例。

二、配置属性实例

下面直接给出代码,代码上都有注释。注:下面的实体主要是为了演示用

  1. 1: //实体
  1. 2: public class Trip
  1. 3: {
  1. 4: public Guid Identifier { get; set; }
  1. 5: public DateTime StartDate { get; set; }
  1. 6: public DateTime EndDate { get; set; }
  1. 7: public decimal CostUSD { get; set; }
  1. 8: public string Description { get; set; }
  1. 9: public byte[] RowVersion { get; set; }
  1. 10: }
  1. 11:  
  1. 12: //复杂类型
  1. 13: public class Address
  1. 14: {
  1. 15: public int AddressId { get; set; }
  1. 16: public string StreetAddress { get; set; }
  1. 17: public string City { get; set; }
  1. 18: public string State { get; set; }
  1. 19: public string ZipCode { get; set; }
  1. 20: }
  1. 21:  
  1. 22: //复杂类型
  1. 23: public class PersonalInfo
  1. 24: {
  1. 25: public Measurement Weight { get; set; }
  1. 26: public Measurement Height { get; set; }
  1. 27: public string DietryRestrictions { get; set; }
  1. 28: }
  1. 29:  
  1. 30: //复杂类型
  1. 31: public class Measurement
  1. 32: {
  1. 33: public decimal Reading { get; set; }
  1. 34: public string Units { get; set; }
  1. 35: }
  1. 36:  
  1. 37: //实体
  1. 38: public class Person
  1. 39: {
  1. 40: public Person()
  1. 41: {
  1. 42: Address = new Address();
  1. 43: Info = new PersonalInfo()
  1. 44: {
  1. 45: Weight = new Measurement(),
  1. 46: Height = new Measurement()
  1. 47: };
  1. 48: }
  1. 49:  
  1. 50: public int PersonId { get; set; }
  1. 51: public int SocialSecurityNumber { get; set; }
  1. 52: public string FirstName { get; set; }
  1. 53: public string LastName { get; set; }
  1. 54: public Address Address { get; set; }
  1. 55: public byte[] Photo { get; set; }
  1. 56: public PersonalInfo Info { get; set; }
  1. 57: public byte[] RowVersion { get; set; }
  1. 58: }
  1. 59:  
  1. 60: //对实体Trip的配置,继承自EntityTypeConfiguration<T>
  1. 61: public class TripConfiguration : EntityTypeConfiguration<Trip>
  1. 62: {
  1. 63: public TripConfiguration()
  1. 64: {
  1. 65: //配置Identifier映射到TripId列,并设为主键,且默认值为newid()
  1. 66: HasKey(t => t.Identifier).Property(t => t.Identifier).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("TripId");
  1. 67: //配置CostUSD的精度为20,小数位数为3
  1. 68: Property(t => t.CostUSD).HasPrecision(20, 3);
  1. 69: //配置Description的长度为500
  1. 70: Property(t => t.Description).HasMaxLength(500);
  1. 71: //配置RowVersion乐观并发检查
  1. 72: Property(t => t.RowVersion).IsRowVersion();
  1. 73: }
  1. 74: }
  1. 75:  
  1. 76: //对实体Person的配置,继承自EntityTypeConfiguration<T>
  1. 77: public class PersonConfiguration : EntityTypeConfiguration<Person>
  1. 78: {
  1. 79: public PersonConfiguration()
  1. 80: {
  1. 81: //配置SocialSecurityNumber不允许为空且乐观并发检查
  1. 82: Property(t => t.SocialSecurityNumber).IsRequired().IsConcurrencyToken();
  1. 83: //配置FirstName不允许为空
  1. 84: Property(t => t.FirstName).IsRequired();
  1. 85: //配置LastName不允许为空
  1. 86: Property(t => t.LastName).IsRequired();
  1. 87: //配置Photo映射到数据库的数据类型为image
  1. 88: Property(t => t.Photo).HasColumnType("image");
  1. 89: //配置RowVersion乐观并发检查
  1. 90: Property(t => t.RowVersion).IsRowVersion();
  1. 91: }
  1. 92: }
  1. 93:  
  1. 94: //对复杂类型Address的配置,继承自ComplexTypeConfiguration<T>
  1. 95: public class AddressConfiguration : ComplexTypeConfiguration<Address>
  1. 96: {
  1. 97: public AddressConfiguration()
  1. 98: {
  1. 99: //配置AddressId映射到AddressId列
  1. 100: Property(t => t.AddressId).HasColumnName("AddressId");
  1. 101: //配置StreetAddress长度为100并映射到StreetAddrress列
  1. 102: Property(t => t.StreetAddress).HasMaxLength(100).HasColumnName("StreetAddress");
  1. 103: //配置State长度为50并映射到State列
  1. 104: Property(t => t.State).HasMaxLength(50).HasColumnName("State");
  1. 105: //配置City长度为50并映射到City列
  1. 106: Property(t => t.City).HasMaxLength(50).HasColumnName("City");
  1. 107: //配置ZipCode映射到ZipCode列,不支持Unicode内容,并设为固定长度为6
  1. 108: Property(t => t.ZipCode).IsUnicode(false).IsFixedLength().HasMaxLength(6).HasColumnName("ZipCode");
  1. 109: }
  1. 110: }
  1. 111:  
  1. 112: //对复杂类型PersonalInfo的配置,继承自ComplexTypeConfiguration<T>
  1. 113: public class PersonalInfoConfiguration : ComplexTypeConfiguration<PersonalInfo>
  1. 114: {
  1. 115: public PersonalInfoConfiguration()
  1. 116: {
  1. 117: //配置DietryRestrictions长度为100
  1. 118: Property(t => t.DietryRestrictions).HasMaxLength(100);
  1. 119: }
  1. 120: }
  1. 121:  
  1. 122: public class BreakAwayContext : DbContext
  1. 123: {
  1. 124: public DbSet<Trip> Trips { get; set; }
  1. 125: public DbSet<Person> People { get; set; }
  1. 126:  
  1. 127: protected override void OnModelCreating(DbModelBuilder modelBuilder)
  1. 128: {
  1. 129: //注册配置
  1. 130: modelBuilder.Configurations.Add(new TripConfiguration());
  1. 131: modelBuilder.Configurations.Add(new PersonConfiguration());
  1. 132: modelBuilder.Configurations.Add(new AddressConfiguration());
  1. 133: modelBuilder.Configurations.Add(new PersonalInfoConfiguration());
  1. 134: base.OnModelCreating(modelBuilder);
  1. 135: }
  1. 136: }

最后生成的数据库结构,如下图所示:

Trips表

People表

—Entity Framework实例详解的更多相关文章

  1. Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

  2. 转:【工欲善其事必先利其器】—Entity Framework实例详解

    开始本篇文章之前,先说一下Entity Framework 6 Alpha1在NuGet中已可用,原文链接http://blogs.msdn.com/b/adonet/archive/2012/10/ ...

  3. 【配置属性】—Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

  4. 【迁移】—Entity Framework实例详解 转

    一.Entity Framework 迁移命令(get-help EntityFramework) Enable-Migrations 启用迁移 Add-Migration 为挂起的Model变化添加 ...

  5. 【迁移】—Entity Framework实例详解

    好久没有在博客园更新博客了,如今都换了新公司.前段时间写了关于EF迁移的文档,今天拿出来作为这个系列的一篇吧. 一.Entity Framework 迁移命令(get-help EntityFrame ...

  6. 【配置关系】—Entity Framework实例详解

    实体间的关系,简单来说无非就是一对一.一对多.多对多,根据方向性来说又分为双向和单向.Code First在实体关系上有以下约定: 1. 两个实体,如果一个实体包含一个引用属性,另一个实体包含一个集合 ...

  7. [转]C#综合揭秘——Entity Framework 并发处理详解

    本文转自:http://www.cnblogs.com/leslies2/archive/2012/07/30/2608784.html 引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的 ...

  8. Linq实战 之 Linq to Sql及Entity Framework操作详解

    Linq实战 之 Linq to Sql及Entity Framework操作详解 一:linq to db的框架 1. linq to sql 2. linq to ado.net entity f ...

  9. C#综合揭秘——Entity Framework 并发处理详解

    引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的错误的一种机制.从 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NET Entity Framework,.NET 都 ...

随机推荐

  1. 【转】GO语言map类型interface{}转换踩坑小记

    原文:https://www.az1314.cn/art/69 ------------------------------------------ mapA := make([string]inte ...

  2. 【组合数学】AGC036C - GP 2

    找性质的能力不行 Problem Statement We have a sequence of $N$ integers: $x=(x_0,x_1,\cdots,x_{N−1})$. Initial ...

  3. getSuperclass与getGenericSuperclass区别

    声明三个类class Person<T, V> {}class Teacher {}class Student extends Person<Student, Teacher> ...

  4. RHEL8 创建本地YUM存储库

    yum 的好处及本地yum的好处不在本文讨论范畴,本文针对rhel8中的新功能yum做简要介绍和配置,在 RHEL 8中分为两个存储库: BaseOS 应用程序流(AppStream) BaseOS中 ...

  5. IDEA中配置Jetty Server

    首先去 Eclipse官网下载Jetty jar包 鼠标移到Jetty上时 点击 Git it (得到它) 点击 .zip等待下载完成 然后 解压出来 接下就让我们 开始 使用IDEA了(创建一个We ...

  6. Codeforces Round #589 (Div. 2) E. Another Filling the Grid(DP, 组合数学)

    链接: https://codeforces.com/contest/1228/problem/E 题意: You have n×n square grid and an integer k. Put ...

  7. 题解 [SDOI2010] 大陆争霸

    题面 解析 这题似乎不是那么难啊 首先,显而易见, 如果要摧毁一个城市,必须要满足两个条件: 机器人摧毁了保护它的城市. 机器人到达了这个城市. 而这两个条件可以同时进行(毕竟有无数机器人) 那么显然 ...

  8. No module named 'pip._vendor.progress.helpers' 的解决方法

    莫名其妙的pip出现故障了 ModuleNotFoundError: No module named ‘pip._vendor.progress.helpers’ 在百度搜索了一圈也没看到这个错误的解 ...

  9. php判断文件是否为txt文件

    可以使用pathinfo方法来通过后缀名进行判断文件类型. /** * 获取文件后缀(如果文件名为11.11,11不是后缀,会默认11为后缀) * $file string 文件路径或者文件名 */ ...

  10. java学习第一天:环境的配置

    1.下载JDK,当前版本下载地址为:http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.htm ...