EF中的Code First

EF中的Code First

  一些概念

? POCO

  POCO(Plain Old CLR Object)的概念是从java的POJO借用而来,而两者的含义是一致的,不同的仅仅是使用的语言不一样。所以POCO的解释就是“Plain Old C# Object”。POJO的内在含义是指那些没有从任何类继承、也没有实现任何接口,更没有被其它框架侵入的对象。

PO

  PO是指持久对象(persistant object持久对象)。持久对象实际上必须对应数据库中的entity,所以和POJO有所区别。比如说POJO是由new创建,由GC回收。但是持久对象是 insert数据库创建,由数据库delete删除的。基本上持久对象   生命周期和数据库密切相关。另外持久对象往往只能存在一个数据库 Connection之中,Connnection关闭以后,持久对象就不存在了,而POJO只要不被GC回收,总是存在的。

ORM

  ORM(Object/Relational Mapping) 对象关系映射,主要是把数据库中的关系数据映射称为程序中的对象

? NHibernate

  NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。所以NHibernate与Entity Framework是很相近的。

Entity Framework

  Entity Framework的全称是ADO.NET Entity Framework,是微软开发的基于ADO.NET的ORM(Object/Relational Mapping)框架。

其架构图如下:

  在接手一个新项目时我们所熟知及习惯使用的设计方式,是在分析需求后开始创建数据库中的表,一旦表确定后变动不会太大或者几乎不再去更改表的结构,后面的模型编写及业务逻辑的编写都在这个基础上进行。这种方式称为Database First。

  而在2011四月发布的Entity Framework 4中存在三种工作方式,他们分别为:Code First, Model First和Database First。其中本文要讨论的Code First就是新增的一种方式。

Code First

  为了支持以设计为中心的开发流程,EF4 还更多地支持以代码为中心 (code-centric) ,我们称为代码优先的开发,代码优先的开发支持更加优美的开发流程,它允许你:

在不使用设计器或者定义一个 XML 映射文件的情况下进行开发。

  ·允许编写简单的模型对象POCO (plain old classes),而不需要基类。

  ·通过"约定优于配置",使得数据库持久层不需要任何的配置

  ·也可以覆盖"约定优于配置",通过流畅的 API 来完全定制持层的映射。

  Code First是基于Entity Framework的新的开发模式,原先只有Database First和Model First两种。Code First顾名思义,就是先用C#/VB.NET的类定义好你的领域模型,然后用这些类映射到现有的数据库或者产生新的数据库结构。Code First同样支持通过Data Annotations或fluent API进行定制化配置。

其他两种设计方式

?   Database First是最老也是应用得最广泛的一种设计方式。如上文提到过的那样,Database First这种方式的设计高度依赖于数据库中表的结构,根据表及表间的关系来创建模型。如果后期需求有所变更或者功能有很大变化的话,需要涉及到更改数据库所付出的代价将会很大,因为之前编写好的代码将不再适用于新的表,我们必需重构以更改代码中的逻辑以适应更改之后的表。

?   Model Firstj是创建ADO.NET实体对象以及它们之间的关系,然后再指定到数据库的映射。这个实体对象即为Model。

在MVC中使用CodeFirst

  这里我将用一个非常简单的例子来演示一下Code First在MVC中的使用,主要还是展示Code First 具体是怎么工作的。

  Note:你可能需要单独安装Entity Framework 4.1

  ADO.NET Entity Framework 4.1 安装文件下载地址:http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8363

  下面我们开始这个例子。既然是Code First,就是以代码为中心进行设计,所以我们并不关心具体的数据库构造到底是怎么样的。我们从分析需求开始,即我们要实现的功能。这里我仅仅是要实现一个展示博客列表的页面,这里我们不关注CRUD的实现,因为这些都可以在MVC里自动生成。这里我们将看到,整个过程我们没有写sql语句,也没有用sql server management studio 在数据库里进行表的设计,但我们运行程序时,这些需要的表就已经自动创建好了,并且我们在页面进行CRUD操作时,也是与数据库里面的数据是完全同步的。

  打开VS2010新建一个MVC3项目,注意环境要设为.Net Framework 4。这里我将项目命名为MvcBlog。

  选择空的模板,View engine我们用ASPX。

  因为Code First需要EntityFramework支持,项目创建好后在引用里面系统已经自动为我们引用了EntityFramework程序集,如果没有需要手动引用进来。

(为了展示完整的目录层结构,在图片上我把中间很多引用去掉换以省略号代替,所以你看到这张图片时不要感到奇怪,我的VS不是特别定制版的)

  我们首先在Model中创建一个博客类来保存一篇博客的基本信息,它包含一个博客标识BlogId, 标题Title还有创建日期CreateDate。

在Model文件夹上右击选择Add->Class。

  在Name中输入Blog再点击Add。

  其中的代码如下:

 1 namespace MvcBlog.Models
 2
 3 {
 4
 5     public class Blog
 6
 7     {
 8
 9         public int BlogId { get; set; }
10
11         public string Title { get; set; }
12
13
14
15         public DateTime CreateDate { get; set; }
16
17     }
18
19 }

  同样的方法我们再新建一个类,命名为BlogEntities.cs,这个类跟Blog类的功能是不同的,我们将在代码里将它定义为从DBContex继承,这样这个BlogEntities上下文类将扮演着与数据库沟通的重要角色,在这里面可以定义需要的表,项目运行后这些表将自动在数据库创建。这里,我们用刚才定义好的Blog来定义一个Dbset,代码如下:

1 public class BlogEntities:DbContext
2
3     {
4
5         public DbSet<Blog> Blogs { get; set; }
6
7     }

 (注意:这里需要在文件顶部添加using System.Data.Entity引用语句才能使用DbContext及DbSet)

  上面我们把模型准备好了,现在定义Controller。但在进行这一步前,我们需要Ctrl+Shift+B编译一下程序,以便系统知道我们之前定义好的Blog类和BlogEntities类。右击Controllers文件夹选择Add->Controller打开添加Controller对话框,将其命名为HomeController(MVC的Controller,当然你也可以随便命名,只不过在打开网页时需要手动输入路径),此刻数据库还没有被创建,并且呆会自动创建后里面也是空的没有数据,我们需要向里面添加一些数据,所以这里模板我们选择带有CRUD(增删除改查)功能的,再将下面的模型类选为Blog,上下文类选为BlogEntities,系统会自动实现CRUD操作,不用我们手动编写。

(注意:之前必需编译一下,才能在这一步的下拉菜单里找到我们已经定义好的类)

单击Add之后,生成的代码大概是这样:

+ ?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

namespace MvcBlog.Controllers

{

    public class HomeController : Controller

    {

        private BlogEntities db = new BlogEntities();

        //

        // GET: /Home/

        public ViewResult Index()

        {

            return View(db.Blogs.ToList());

        }

        //

        // GET: /Home/Details/5

        public ViewResult Details(int id)

        {

            Blog blog = db.Blogs.Find(id);

            return View(blog);

        }

        //

        // GET: /Home/Create

        public ActionResult Create()

        {

            var blog = new Blog();

            return View();

        }

        //

        // POST: /Home/Create

        [HttpPost]

        public ActionResult Create(Blog blog)

        {

            if (ModelState.IsValid)

            {

                db.Blogs.Add(blog);

                db.SaveChanges();

                return RedirectToAction("Index"); 

            }

            return View(blog);

        }

        

        //

        // GET: /Home/Edit/5

 

        public ActionResult Edit(int id)

        {

            Blog blog = db.Blogs.Find(id);

            return View(blog);

        }

        //

        // POST: /Home/Edit/5

        [HttpPost]

        public ActionResult Edit(Blog blog)

        {

            if (ModelState.IsValid)

            {

                db.Entry(blog).State = EntityState.Modified;

                db.SaveChanges();

                return RedirectToAction("Index");

            }

            return View(blog);

        }

        //

        // GET: /Home/Delete/5

 

        public ActionResult Delete(int id)

        {

            Blog blog = db.Blogs.Find(id);

            return View(blog);

        }

        //

        // POST: /Home/Delete/5

        [HttpPost, ActionName("Delete")]

        public ActionResult DeleteConfirmed(int id)

        {           

            Blog blog = db.Blogs.Find(id);

            db.Blogs.Remove(blog);

            db.SaveChanges();

            return RedirectToAction("Index");

        }

        protected override void Dispose(bool disposing)

        {

            db.Dispose();

            base.Dispose(disposing);

        }

    }

}

  

  视图已经自动添加在了Views文件夹下,到此我们的程序已经能够工作了,虽然我们似乎什么都没做。在运行前我们可以打开Sql server management studio (或者在VS里用服务器管理器连接到你本地的数据库)查看一下以确定数据库里还没有我们程序里需要的Blog表。然后我们Ctrl+F5运行网站。

  页面显示出了我们在Blog中定义的Title字段和CreateDate字段,但由于还没有数据来进行显示,所以只有标题。

  这个时候,我们断开数据库再重新连接,就会发现EF创建了一个程序命名空间为名称的数据库MvcBlog.Models.BlogEntities,里面包含我们用Dbset定义的Blogs表。表中的列也正好与我们在Blog类中定义的字段相对应。

  仔细观察你会发现,它自动将BlogId定义为了主键,这是EF的convention在起作用,如果我们没有显示地指定数据库的连接字符串等配置信息,这些值将会遵从EF里的约定进行取值,比如这里的数据库名 MvcBlog.Models.BlogEntities。

  这样的名称当然不是我们想要的,而且,如果我们本地安装了多个数据库实例的话,我们也希望指定项目将数据创建在我们想要的实例当中。要覆盖默认的约定,我们只需在Web.config(注意:不是Views文件夹下的Web.config)里添加一下对数据库的配置信息,代码如下:

<connectionStrings>

    <add name="BlogEntities"

        connectionString="server=(local)\sqlexpress;database=MvcBlog;integrated security=true;"

        providerName="System.Data.SqlClient"/>

  </connectionStrings>

  注意上面的name应和Models中的定义的上下文类名称相同,这样才能使EF正常工作。server换成你本机数据库实例的名字。现在我们可以看到在先前那个数据库上方它生成了我们重新命名的数据库。

  重新运行程序,我们在页面中点击Create New来添加几条数据。

  添加完数据后我们再返回去看数据库中的变化。

  如图,数据库中已经保存了我们在页面上添加的数据。

  到这里大家已经看到了Code First 设计方式的大概过程。现在我们来回顾一下,之前所做的操作,将会更加明白这一过程是怎样进行的,特别是代码优先是如何做到在没有数据库支持的情况下先建立数据模型,然后再对数据库进行操作的。

  首先我们在Models中创建了所需要的数据模型Blog类,里面包含的字段将映射到以后数据库表中的相应列。

  接下来同样是在Models文件夹中,我们定义了一个最关键的BlogEntities上下文类,它继承自System.Data.Entity下的DbContext,它将我们的数据模型映射到数据库中,将代码中的数据持久化。

  最后,在页面上进行添加数据时,页面将表单数据通过Blog类型传回Controller里面相应的方法,这里是处理Post回传的Create Action,它接收传回来的数据,通过调用db.SaveChanges()进行了数据的保存。这里db是BlogEntities上下文类的一个实例。通过BlogEntities上下文类,我们进行的RUD操作将反应到数据库中,完成了从代码到数据库的更新过程。

说明:操作ORACLE数据库配置更复杂些,下次再介绍!

时间: 2024-10-25 22:05:51

EF中的Code First的相关文章

EF 中 Code First 的数据迁移以及创建视图

写在前面: EF 中 Code First 的数据迁移网上有很多资料,我这份并没什么特别.Code First 创建视图网上也有很多资料,但好像很麻烦,而且亲测好像是无效的方法(可能是我太笨,没搞成功),我摸索出了一种简单有效的方法,这里分享给大家. EF是Entity Framework(实体框架)的简写,是微软出品的用来操作数据库的一个框架,会ASP.NET MVC的朋友对他肯定都不陌生.由于学艺不精,我对EF存在一疑虑,就不以[提问]的方式来问了,我以[总结]的方式来表达,如果总结有误的地

EF中三大开发模式之DB First,Model First,Code First以及在Production Environment中的抉择

一:ef中的三种开发方式 1. db first... db放在第一位,在我们开发之前必须要有完整的database,实际开发中用到最多的... <1> DBset集合的单复数... db => model 2. model first... 根据model生成数据库,和我们的sqlserver的可视化类视图是一样的... 其实sqlserver也是有自己的类视图... 如果用ef来创建: <1> 生成类图.. <2> 根据模型生成数据库... 3. code f

1.Relationship in Entity Framework Using Code First Approach With Fluent API【使用EF Code-First方式和Fluent API来探讨EF中的关系】

In this article, you will learn about relationships in Entity Framework using the Code First Approach with Fluent API. 在这篇文章中,你将会学习到使用EF Code-First方式和Fluent API来探讨EF中的关系(一对一,一对多,多对多). Introduction[介绍] A relationship, in the context of databases, is a

2. Code First Migrations With Entity Framework【EF中 Code-First 方式的数据库迁移】

前面的文章中,学习了EF 中的几种关系,一对一,一对多,多对多.但是相信大家肯定会有疑问: 1.我难道每次都要创建数据库么? 2.我怎么样从已经存在的表中,添加字段和移除字段呢? 3.当我向表中,添加字段或者移除字段,我怎么来避免丢失数据呢? 4.当数据库发生改变的时候,我怎么获取到创建数据库的脚本呢? 不用着急,这篇文章,我会向大家一一讲到: 首先,说说我们为什么要使用数据库迁移技术吧,因为我们的实体总是变动地很频繁,在上篇文章中,我们使用了数据库初始化策略来做,也就是每次当数据库不存在的时候

使用 EF Power Tool Code Frist 生成 Mysql 实体

原文:使用 EF Power Tool Code Frist 生成 Mysql 实体 1,在要生成的项目上右键   2,   3,   4,   5,  生成后的效果     已知问题: 1,在Mysql数据表中 tinyint(1) ,会被映射成为 C# bool ,这样造成一些数据信息的丢失. 这个问题应该是EF 工具的问题,暂时没有找到解决方案.      手工去修改生成的实体是不经济的,下次再更新时候,又会变成 bool型 .      所以解决的办法就是修改数据库字段型 ,一般情况下,

EF中的transaction的使用范例

注意一点: 在EF中使用事物后,对于一个新增的model,在saveChanges后,可以得到该实体的自增ID,但在提交事物之前, 该数据并没有真正的新增到DB中,但此时可以得到model新增的自增ID,程序中可以使用,很方便! 例如下面的series实体在新增时,下面新增level时就可以直接使用,但此时的series并没有真正的新增到db中. /// <summary>        /// 导入汽车维护数据        /// </summary>        /// &

EF中执行sql语句

EF原理 EF 会自动把 Where().OrderBy().Select()等这些编译成"表达式树(Expression Tree)",然后会把表达式树翻译成 SQL 语句去执行.(编译原理,AST)因此不是"把数据都取到内存中,然后使用集合的方法进行数据过滤",因此性能不会低.但是如果这个操作不能被翻译成 SQL 语句,则或者报错,或者被放到内存中操作,性能就会非常低 跟踪EF的查询Sql语句: DbContext 有一个 Database 属性,其中的 Log

EF中逆变和协变

EF中的增删改查: 实现步骤: 1.声明一个EF的上下文. bjhksjEntities dbContext = new bjhksjEntities(); 2.声明一个实体. HKSJ_USERS user = new HKSJ_USERS(); user.LoginName = "ssss"; user.Mail = "ssss"; user.PassWord = "ssss"; user.Plane = "ssss";

数据库事务及其EF中如何处理事务

一.基础知识 1)         使用事务级别ReadUnCommited 会产生脏读现像,意味着读取到的为UnCommited(未提交)的数据.怎么理解呢?在使用该隔离级别的事务开始后.更新了数据库某一行的数据,但是事务的工作量比较大,后续还有一大堆代码还没执行完呢.不巧的是有个哥们过来读数据了,这个时候读到的就是未提交的值,如果后继工作一切正常,也没什么影响.一旦后面的代码执行中出错,就会产生不一致的错误,适用于对事务极度自信的情况下,特点为可读不可改.关于不可改需解释一下,MS SQL中