前两回合,我们讨论学习了如何采用Entity Framework在没有数据库的情况下自己写一些实体类,然后通过CodeFirst反向生成对应的数据库。通过CodeFirst,我们摆脱了edmx文件,没有了繁琐的Xml关系映射,使代码变得无比的清晰,修改起来也变得更加容易。
在前两篇文章中,我们的数据库都是通过反向生成的,也就是说,属于一个New Database(新数据库),那么,对于一个Exist Database(已存在的数据库),我们又应该怎么办呢?本节文章,我们将对 Code First to an Existing Database 做出讨论学习。
本回合我们将讨论:
1、介绍使用“Entity Framework Power Tools“ 工具
2、EF CodeFirst to Existing Database 的快速入门
3、了解”Entity Framework Power Tools“ 工具为我们做了哪些事
案例代码可以点击这里下载
1、Entity Framework Power Tools 工具
在看完本节的导读时,也许你已经有了自己的一点想法:“按照我的数据库结构,自己手写出一些对应的实体Model,然后再写一个继承自DbContext的上下文……”。没错,恭喜你,你的想法理论上确实是可行的,至少在表不太多的情况下是可行的。但是,如果这个数据库的表有很多呢,数目已经达到了上百个或者更多呢?明显的,我们如果想自己手写实体和上下文,那无疑是一件巨大的工程。
既要懂得原理,也要懂得效率;我们要做某一件事,必须先要懂得它的原理,为什么要这么做,知其然知其所以然,所谓“原理先行”嘛。懂了了原理之后,我们需要提高效率,这在当今这个效率就是金钱的时代中尤为重要。
不扯开话题,下面我为大家介绍一款工具,它的名字就是:“Entity Framework Power Tools”,它的可以实现,对数据库中已存在的表自动的生成相应的实体和上下文。这款工具的下载地址各位读者可以点击这里获得最新版的下载。
各位读者下载下来之后,双击打开安装,然后再重启Visual Studio实例,就可以使用啦。
2、快速入门(快速案例)
我们新建一个解决方案
再看看我们的数据库,这里我采用上回合反向生成的数据库(由于VS自带的数据库管理器用起来速度太慢,我额外装了一个“SQL Server Management Studio”,数据库实例还是采用原先的轻量级数据库LocalDB,区别的仅仅是管理工具不同,数据库实例还是一样,各位读者不必感觉疑惑)
右键点击解决方案,我们发现了一些新东西
这就是我们刚才安装的EF工具,顺着点击进去,我们会弹出一个SQL Server的连接窗口,填写好相应的连接信息,点击确定
稍等一会儿,系统会自动的连接数据库,然后遍历所有的表,并根据表结构生成一些代码。
我们可以看到,解决方案中多了一个“Model”文件夹,里面包含有上下文、一些Model、“Mapping”文件夹以及其下的Map文件(映射文件)
我们先不解释里面的东西,先在Program中写调用代码,解释留到第三节再解析。
我们在Program中写如下调用代码:
class Program { static void Main(string[] args) { using (var db = new CodeFirst_2013_3_23BlogContextContext()) { Console.Write("Enter a name for a new blog:"); var name = Console.ReadLine(); var blog = new Blog { BlogName = name }; db.Blogs.Add(blog); db.SaveChanges(); var result = from b in db.Blogs select b; foreach (var item in result) { Console.WriteLine(item.BlogName); } } Console.ReadKey(); } }
F5,调试:
可以正常执行(上面那个小蝶惊鸿是上回合CodeFirst操作中遗留下来的数据)
3、EF工具帮我们生成了什么
上一节我们是一个快速入门,这一节我们看看EF Tool帮我们生成了些什么代码。
先看一下App.config
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <connectionStrings> <add name="CodeFirst_2013_3_23BlogContextContext" connectionString="Data Source=(localdb)\mydb;Initial Catalog=CodeFirst_2013_3_23.BlogContext;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /> </connectionStrings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="v11.0" /> </parameters> </defaultConnectionFactory> </entityFramework> </configuration>
系统帮我们自动的填写配置信息,值得注意的是“connectionStrings”节点,这里配置了EF的连接字串,在初始化上下文的对象时,上下文的构造函数会默认的传入这里的连接字串。
<connectionStrings> <add name="CodeFirst_2013_3_23BlogContextContext" connectionString="Data Source=(localdb)\mydb;Initial Catalog=CodeFirst_2013_3_23.BlogContext;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /> </connectionStrings>
进入“Model”文件夹
这里生成了一些实体类文件:
Post实体:
public partial class Post { public int PostID { get; set; } public string Title { get; set; } public string Content { get; set; } public int BlogID { get; set; } public virtual Blog Blog { get; set; } }
Blog实体:
public partial class Blog { public Blog() { this.Posts = new List<Post>(); } public int BlogID { get; set; } public string BlogName { get; set; } public string Url { get; set; } public virtual ICollection<Post> Posts { get; set; } }
Type实体:
public partial class Type { public int TypeID { get; set; } public string TypeName { get; set; } }
User实体:
public partial class User { public string UserName { get; set; } public string Display_Name { get; set; } }
还有上下文类CodeFirst_2013_3_23BlogContextContext:
public partial class CodeFirst_2013_3_23BlogContextContext : DbContext { static CodeFirst_2013_3_23BlogContextContext() { Database.SetInitializer<CodeFirst_2013_3_23BlogContextContext>(null); } public CodeFirst_2013_3_23BlogContextContext() : base("Name=CodeFirst_2013_3_23BlogContextContext") { } public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } public DbSet<Type> Types { get; set; } public DbSet<User> Users { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new BlogMap()); modelBuilder.Configurations.Add(new PostMap()); modelBuilder.Configurations.Add(new TypeMap()); modelBuilder.Configurations.Add(new UserMap()); } }
该上下文构造方法调用了父类DbContext的构造方法,传入配置文件中的数据库连接字串来连接需要的数据库。
(反编译DbContext得知其构造方法实际上是重载的方法,我们可以传入多种的参数形式,这里我们不做过多的介绍)
最后,我们进入“Mapping”文件夹
里面包含的都是实体与数据库,属性与字段映射的关系文件,作用跟使用edmx文件时,那繁琐的XML映射作用是一样的,不过,采用CodeFirst方式生成的关系映射,代码都是C#语言的,并且看起来相当清晰,以后重构起来也比edmx的XML方便得多。
至此,本回合的CodeFirst to Existing Database已经讨论讲解完毕,个人能力有限,可能文中会有错漏的地方,欢迎各位朋友指正以及提出建议。