初试Code First(附Demo)
写在前面
以前逛园子的时候,很多大牛写的一些东西,什么AOP、DDD之类的,看过之后一头雾水,远望大牛,回过头看看自己,原来程序员的差距还可以这么大。每个程序员都有个大牛梦想,当然小菜我也是,只是还在开始的路上。
因为前几天研究easyui,准备写个mvc+ef+easyui的简单示例,当然这对很多人来说很简单,有段时间也研究过别人写的,但这是小菜我第一次自己写,勿喷。而且这周安排给自己的任务:设计模式第五篇-控制反转(ioc),前段时间做些其他方面的事,设计模式也好久没写了,所以这周必须把它完成,想研究完ioc之后,试着再写上面的简单示例,把ioc融入到mvc中,想想应该有搞头。
关于Code First,昨晚无意间看到一位园友翻译的相关教程:http://www.cnblogs.com/qouoww/archive/2011/12/31/2309066.html,这边小弟先谢过,前面几篇还可以看下去,但是后面几篇就有点不知所云了,学习是一方面,实践是另一方面,做的过程中才能学到更多的东西,这边也试着写个关于Code First的小示例。
自己动手,丰衣足食。
新建项目
我使用的是vs2012,如果使用vs2010需要安装NuGet。
Nuget是一个.NET平台下的开源的项目,它是Visual Studio的扩展。在使用Visual Studio开发基于.NET Framework的应用时,Nuget能把在项目中添加、移除和更新引用的工作变得更加快捷方便。
新建-项目-Visual C#-windows-控制台应用程序,命名为:CodeFirstDemo。
这边需要注意的是:选择.net framework的时候要4.0以上版本,要不然下面NuGet安装EntityFramework扩展的时候会报创建项目版本底无法完成安装的错误,.net framework改成4.0就可以了,但是换了一台电脑3.5版本测试安装又是好的,不知是个什么情况,反正.net framework版本最好选择4.0以上。
安装EntityFramework程序包
新建好CodeFirstDemo项目后,我们先来安装EntityFramework,项目-管理NuGet程序包-联机-搜索“EntityFramework”,下载安装。
安装完成后会在项目下自动添加EntityFramework引用:
在Program.cs代码文件中添加下面命名空间:
1 using System.Data.Entity;
创建模型
Code First顾名思义就是代码先行的意思,除了Code First,还有Model First、DatabaseFirst,关于他们几个的区别:http://blog.bossma.cn/csharp/when-is-code-first-not-code-first/。
下面我们在Program.cs中创建几个模型,平常我们可以分离出来。
1 public class New 2 { 3 public int NewId { get; set; } 4 public string Title { get; set; } 5 6 public int NewTypeId { get; set; } 7 public virtual NewType NewType { get; set; } 8 } 9 10 public class NewType 11 { 12 public int NewTypeId { get; set; } 13 public string Name { get; set; } 14 15 public int BlogId { get; set; } 16 public virtual List<New> New { get; set; } 17 }
NewId和NewTypeId在创建的时候会做为表的主键,因为包含有ID关键字,如果不包含的话,需要我们指定主键,要不然创建就会报未找到主键的错误,添加命名空间:
1 using System.ComponentModel.DataAnnotations;
并在属性前添加[Key]标注,指示此字段作为主键,例如:
1 [Key] 2 public string UserName { get; set; }
当然除了Key,System.ComponentModel.DataAnnotations命名空间下还有其他的Attribute,这边就不多说,可以查看msdn有关教程:http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx。
需要注意的另外一点,上面定义模型属性的时候有virtual关键字,表示延迟加载,我的理解是这样:当我访问主实体的时候,启动延迟加载,而不会查询数据库的子实体,只有要访问它的时候才会去数据库查询加载,泛型List表示此实体是一对多的关系。
EF默认是启动延迟加载的,我们如果不需要也可以手动禁止:
1 db.Configuration.LazyLoadingEnabled = false;,
创建上下文DbContext
我对EF中上下文的理解:可以把上下文看成一个数据库控制器,我们可以在其中查询、更改、删除数据,然后通过连接获取或是提交。就像是遥控车的遥控器一样,EF是这个遥控器的核心部件,天线是连接字符串,遥控车是数据库,这个比喻可能不是很恰当,但就是这个意思,大家都懂得。
1 public class NewsContext : DbContext 2 { 3 public DbSet<New> News { get; set; } 4 public DbSet<NewType> NewTypes { get; set; } 5 }
DbSet表示上下文中给定类型的所有实体的集合或可从数据库中查询的给定类型的所有实体的集合,就像是一个包裹,需要什么东西就往里面装什么东西。
创建数据库、读/写数据
在Program.cs的Main方法中填写代码:
1 using (var db = new NewsContext()) 2 { 3 Console.Write("输入新闻类型标题: "); 4 var name = Console.ReadLine(); 5 6 var type_Model = new NewType { Name = name }; 7 db.NewTypes.Add(type_Model); 8 db.SaveChanges(); 9 10 Console.WriteLine("查询新闻类型标题:"); 11 var search_type = Console.ReadLine(); 12 var query = from b in db.NewTypes 13 where b.Name == search_type 14 select b; 15 16 Console.WriteLine("查询结果:"); 17 foreach (var item in query) 18 { 19 Console.WriteLine(item.Name); 20 } 21 22 Console.ReadKey(); 23 }
上面代码创建一个上下文对象实例,通过该实例添加一个新闻实体,然后通过输入的值,linq查询结果输出。
通过上面的操作,我们并没有创建什么连接字符串和数据库操作,但是打开数据库就可以看到我们通过Code First创建的数据库了。
我当时做的时候,运行代码没有错误,但是用.\SQLEXPRESS和localhost登陆都看不到数据库,安装vs2012就给自动安装了localdb,因为我本地没 .\SQLEXPRESS,MSDN相关注解:
- 如果本地 SQL Express 实例可用(默认情况下随 Visual Studio 2010 安装),则 Code First 已对该实例创建了数据库
- 如果 SQL Express 不可用,则 Code First 将尝试使用 LocalDb(默认情况下随 Visual Studio 2012 安装)
配置连接字符串
通过上面默认生成数据库规则可以看出,数据库名是项目命名空间+上下文,有时候我们需要自己定义生成数据库名称,或是生成数据库到指定的服务器,而且有时候数据库迁移了,我们不能再重新生成一遍吧,这时候我们就要自定义数据库连接字符串了:
1 <connectionStrings> 2 <add name="NewContext" providerName="System.Data.SqlClient" connectionString="Server=.\SQLEXPRESS;Database=CodeFirstDemoDB;Trusted_Connection=true" /> 3 </connectionStrings>
需要注意的是:连接字符串的名称必须要和上下文一致,而且connectionStrings必须放在configuration节点内的最下面,如果放在最上面会报下面这种错误:
我们重新按照上面的操作运行程序,就可以在指定的服务器.\SQLEXPRESS,生成指定的数据库CodeFirstDemoDB。
Code First 迁移
关于Code First 迁移其实就是我们在更改模型的时候,数据库要相应的更改,打开工具-库程序包管理器-程序包管理器控制台。
1,例如我们上面创建NewTypes表的时候,没有指定字段的长度,默认是创建字段类型是nvarchar(MAX),有时候我们觉得字段长度太长,需要修改一下字段长度,不要直接去修改数据库,而是在模型中修改:
1 [MaxLength(50)] 2 public string Name { get; set; }
MaxLength就是上面我们说到DataAnnotations命名空间下的类型,这边我们注意下,我们在生成数据库的时候添加了一条数据,Name字段值是“newtype one”,看看我们修改字段长度后,字段值是否发生变化?
2,在程序包管理器控制台输入“Enable-Migrations”命令来启用迁移,运行完成后在项目中会创建一个Migrations文件夹,下来有两类文件:
- Configuration.cs — 此文件包含“迁移”将用来迁移 BloggingContext 的设置。在本演练中不需要进行任何更改,但是,在此处可以指定种子数据、为其他数据库注册提供程序、更改生成迁移的命名空间等。
- <时间戳>_InitialCreate.cs — 这是第一个迁移,它表示已经应用于数据库的更改。应用更改的目的是将其从空数据库迁移至包含博客和文章表的数据库。尽管我们让 Code First 自动创建这些表,现在我们选择“迁移”(已转化为一次“迁移”)。Code First 还在本地数据库中记录:该“迁移”已经应用。文件名中的时间戳用于排序。
需要注意的是:在我们生成数据库的时候,除了New和NewType表外,还有一个系统生成表__MigrationHistory,从表名上就可以看出是迁移历史记录表。
3,在程序包管理器控制台输入“Add-Migration Update-NewType-Name”命令,Add-Migration表示增加一个迁移,后面是迁移名称,这个我们可以随便写,运行后会自动检测模型和数据库发生的变化,在Migrations文件夹下会生成一个“201403290930423_Update-NewType-Name.cs”文件,打开我们可以看到更新内容:
1 public partial class UpdateNewTypeName : DbMigration 2 { 3 public override void Up() 4 { 5 AlterColumn("dbo.NewTypes", "Name", c => c.String(maxLength: 50)); 6 } 7 8 public override void Down() 9 { 10 AlterColumn("dbo.NewTypes", "Name", c => c.String()); 11 } 12 }
从上面可以看出就是我们上面修改模型的内容,当然你也可以在这上面直接修改,比如你再加一个更新,可以一起提交到数据库。
4,在程序包管理器控制台输入“Update-Database”命令,表示将所有的迁移应用到数据库,打开数据库,我们看一下效果:
从上面可以看出,字段Name的类型已经修改为nvarchar(50),而且字段值并没有发生变化,可以证明,Code First迁移并不是删除数据库再创建。
Code First迁移除了上面说的字段类型修改还有很多内容,比如添加字段,删除字段,删除表等等,但都是大同小异,可以举一反三。
示例Demo下载
下载地址:http://pan.baidu.com/s/1i3DS9b3
后记
凡事贵在开始,更贵在坚持,与你共勉。。。
如果你觉得本篇文章对你有所帮助,请点击右下部“推荐”,^_^
微信公众号:你好架构
出处:http://www.cnblogs.com/xishuai/
公众号会不定时的分享有关架构的方方面面,包含并不局限于:Microservices(微服务)、Service Mesh(服务网格)、DDD/TDD、Spring Cloud、Dubbo、Service Fabric、Linkerd、Envoy、Istio、Conduit、Kubernetes、Docker、MacOS/Linux、Java、.NET Core/ASP.NET Core、Redis、RabbitMQ、MongoDB、GitLab、CI/CD(持续集成/持续部署)、DevOps等等。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。