关于Entity Framework 的code first 模式,相信大家都不陌生了.本文就来看看实体继承在 codefirst里的用法.
这里为了方便,选用的是 VS2013 + SQL SERVER 2014 LocalDb, 查看数据用 SQL Server Management Studio 2014
工程我们选用最简单的控制台.
新建完成控制台项目(这里以 EF_CodeFirst_Test 命名)以后,添加 EF 的库,可以用NuGet 的界面添加,也可以用命令,这里用命令添加
在程序包管理器控制台(工具 –> NuGet程序包管理器 –> 程序包管理器控制台) 输入
Install-Package EntityFramework EF_CodeFirst_Test#换上你自己的项目名
接下来,在app.config里加入连接字符串
<add name="CodeFirstModel" connectionString="data source=(LocalDb)\MSSQLLocalDb;initial catalog=TestDb;integrated security=True;multipleactiveresultsets=True;application name=EntityFramework" providerName="System.Data.SqlClient" /> <!-- 同样的,换上你自己的数据库 -->
基类型
public class BaseClass { public long ID { get; set; } public string Name { get; set; } }
三个扩展类,这里为了合并一些表字段,加入了 注解,不然EF会把不同子类里的同名字段后面加上1 2 3 等的数字来区分.加入注解可以强制不同的子类在相同的类型下使用同一字段.
注解相关的命名空间如下
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema;
这里要说明一下,在.net 4.5中 Schema里的一些字段放到了自带的类库里,而在.net 4 及.net 3.5 里是没有的,如果你用一个版本建立了项目,又切换了.net 版本,记得重新安装EF,以保证不要出现同一个类在两个库中同时出现导致无法编译.
下面是几个扩展类
public class ExtendClass:BaseClass { public string DescriptionString { get; set; } [Required] [Column("LongNum")] public long LongNum { get; set; } } public class ExtendClass2 : BaseClass { [Column("Version")] public string Version { get; set; } [Required] [Column("IntNum")] public int IntNum { get; set; } } public class ExtendClass3 : BaseClass { [Column("Version")] public string Version { get; set; } [Required] [Column("IntNum")] public int IntNum { get; set; } [Required] [Column("LongNum")] public long LongNum { get; set; } }
最后是数据库上下文
public partial class CodeFirstModel : DbContext { public CodeFirstModel() : base("name=CodeFirstModel") { } public virtual DbSet<ExtendClass> ExtendClass { get; set; } public virtual DbSet<BaseClass> BaseClass { get; set; } public virtual DbSet<ExtendClass2> ExtendClass2 { get; set; } public virtual DbSet<ExtendClass3> ExtendClass3 { get; set; } }
在Main函数里加入下面代码并执行
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<CodeFirstModel>()); using (var context = new CodeFirstModel()) { context.Database.Initialize(true); }
然后我们可以在 SQL Server Management Studio 里看到数据库,并且还有两个表
从这张表上不难看出,在同一个基类下面继承出的不同实体, code first 会为我们创建同一张表来存储他们.第一个表是code first 的工作表,仅与模型的更新有关.第二个表者是真正的实体表.
让我们看看这个表的构成.
我们会发现,所有的子类的字段都在这里,因为我们用注解合并了一些数据字段,不然同名的字段会出现多个,并且后面补1,2,3 这些数字来区分.
子类中虽然我们在字段上标了[Required],但是表中的字段仍然是可空的.不能想到,因为在这个实体里是必须的,但是其它的子类里就不一定了,所以,只有其类的[Required]标注会让EF 创建一个not null的字段.
在Main 函数里插入点数据吧
using(CodeFirstModel db = new CodeFirstModel()) { BaseClass bc = new BaseClass { Name = "" }; db.BaseClass.Add(bc); ExtendClass bc1= new ExtendClass() { Name = "王二", DescriptionString = "麻子" }; db.ExtendClass.Add(bc1); ExtendClass2 bc2 = new ExtendClass2 { Name = "Sqlserver", Version = "2014" }; db.ExtendClass2.Add(bc2); db.SaveChanges(); }
我们再来看看数据库里的数据
好的,都存进去了,让我们试试往基类的实体集里插入子类实体
修改Main 函数里添加的部分代码
using(CodeFirstModel db = new CodeFirstModel()) { //BaseClass bc = new BaseClass { Name = "" }; //db.BaseClass.Add(bc); //ExtendClass bc1= new ExtendClass() { Name = "王二", DescriptionString = "麻子" }; //db.ExtendClass.Add(bc1); //ExtendClass2 bc2 = new ExtendClass2 { Name = "Sqlserver", Version = "2014" }; //db.ExtendClass2.Add(bc2); ExtendClass3 bc3 = new ExtendClass3 { Name = "C3", Version = "9981", IntNum = 3000, LongNum = 0xFFFFFFFFFFL }; db.BaseClass.Add(bc3); db.SaveChanges(); }
执行后查看数据库
然后我们发现,往基类的实体集里插子类实体,跟往子类的实体集中插入是一样的.
修改Main 函数与实体操作相关部分
using(CodeFirstModel db = new CodeFirstModel()) { //BaseClass bc = new BaseClass { Name = "" }; //db.BaseClass.Add(bc); //ExtendClass bc1= new ExtendClass() { Name = "王二", DescriptionString = "麻子" }; //db.ExtendClass.Add(bc1); //ExtendClass2 bc2 = new ExtendClass2 { Name = "Sqlserver", Version = "2014" }; //db.ExtendClass2.Add(bc2); //ExtendClass3 bc3 = new ExtendClass3 { Name = "C3", Version = "9981", IntNum = 3000, LongNum = 0xFFFFFFFFFFL }; //db.BaseClass.Add(bc3); //db.SaveChanges(); foreach (var item in db.BaseClass) { var cbc3 = item as ExtendClass3; if (cbc3 != null) { Console.Write(cbc3.ID); Console.Write(":\t"); Console.WriteLine(cbc3.Name); } } }
我们可以看到执行的结果
看到了吧,从基类的实体集里读到的,实际上是子类实体.是可以向下转型到对应的子类的.当然,向上转型就不说了.
Entity Framework 的 codefirst 模式让我们可以把数据库中的实体当成是本地的实体来用.无疑,这让我们的代码有了更大的灵活性.但是同时,也让数据库看起来不那么友好了,因为里面多了实体映射的字段.
ORM框架在一定程度上屏蔽了数据库的差异,但同时也屏蔽了一些数据库的优势.而codefirst 更是让一些复杂的数据切分及用存储过程加速处理变得不那么友好了.引用一句老话,不要为了做IT为做IT,当我们的ORM无法快速的达到我们预期的目的时,不妨把ORM 拿掉,用最原始的驱动加上手写的SQL和存储过程来做应用.