EF应用一:Code First模式

EF的核心程序集位于System.Data.Entity.dll和System.Data.EntityFramework.dll中。
支持CodeFirst的位于EntityFramework.dll中。
通常使用NuGet Package Manager来添加这些程序集。

如果没有数据库:
1、先写代码,自动创建数据库。
2、如果代码有变化,自动删除数据库重建,或者是使用迁移功能更改已有数据库。
如果已有数据库:
1、使用EF PowerTools反向工程生成模型。

下面的示例程序中将通过一个控制台程序演示如何通过Code First模式创建一个数据库,并执行简单的增删改查操作。

一、创建一个控制台应用程序,命名为CodeFirstAppDemo。

二、安装Entity Framework,添加对Code First的支持

1、通过Nuget包管理器控制台进行安装

选择“工具”->Nuget程序包管理器->程序包管理器控制台,下面将会打开程序包管理器控制台窗口:

输入命令:Install-Package EntityFramework进行安装。

2、通过可视化界面进行安装

在项目上面右键选择管理Nuget程序包:

选择EntityFramework,点击“安装”按钮进行安装:

安装完以后,项目引用里面将会出现EntityFramework程序集:

如果安装完以后,项目引用里面没有这两个dll,一定要检查为什么没有安装成功,因为下面的程序中要用到DbContext类,该类位于EntityFramework程序集中。

三、根据.NET中的类来创建数据库。

经过上面的步骤之后,我们就可以开始写代码了。在写代码之前,要始终记得:每个实体类就是相应的数据表中的一行数据,该实体类的属性对应的就是数据表中的列。

1、创建EDM实体数据模型

在项目上右键->添加->新建文件夹,命名为Models,存放相应的实体类。在Models文件夹下面新建两个实体类:Category和Product,Category里面包含一个类型是Product的集合属性,两个实体类的属性分别如下:

Category类:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5
 6 namespace CodeFirstAppDemo.Models
 7 {
 8     /// <summary>
 9     /// 产品分类表
10     /// </summary>
11     public class Category
12     {
13         /// <summary>
14         /// 分类ID
15         /// </summary>
16         public int CategoryId { get; set; }
17
18         /// <summary>
19         /// 分类名称
20         /// </summary>
21         public string CategoryName { get; set; }
22
23         /// <summary>
24         /// 产品
25         /// </summary>
26         public List<Product> ProductList { get; set; }
27     }
28 }

Produce类:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5
 6 namespace CodeFirstAppDemo.Models
 7 {
 8     /// <summary>
 9     /// 产品类
10     /// </summary>
11     public class Product
12     {
13         /// <summary>
14         /// 产品Id
15         /// </summary>
16         public int Id { get; set; }
17
18         /// <summary>
19         /// 产品名称
20         /// </summary>
21         public string ProductName { get; set; }
22
23         /// <summary>
24         /// 产品价格
25         /// </summary>
26         public decimal Price { get; set; }
27
28         /// <summary>
29         /// 出版日期
30         /// </summary>
31         public DateTime PublicDate { get; set; }
32     }
33 }

我们需要定义和期望的数据库类型相匹配的属性。上面的例子中,.Net中的int类型会映射到SQL Server中的int类型,string类型会映射到所有可能的字符类型,decimal和Datetime也和SQL Server中的一样。大多数时候,我们不需要关心这些细节,我们只需要编写能够表示数据的模型类就行了,然后使用标准的.Net类型定义属性,其他的就让EF自己计算出保存数据所需要的RDBMS类型。

2、创建数据上下文

接下来我们创建数据库上下文,它是数据库的抽象。目前,我们有两张张表Category和Product,因而要给该数据库上下文定义两个属性来代表这两张表。再者,一张表中一般肯定不止一条数据行,所以我们必须定义一个集合属性,EF使用DbSet来实现这个目的。

在项目上右键->添加->新建文件夹,命名为EFDbContext,用来存放数据库上下文类。添加类Context,并使该类继承自DbContext类。DbContext位于EntityFramework.dll程序集中。

Context类代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data.Entity;
 6 using CodeFirstAppDemo.Models;
 7
 8 namespace CodeFirstAppDemo.EFDbContext
 9 {
10     public class Context : DbContext
11     {
12         /// <summary>
13         /// 1、创建构造函数,构造函数继承DbContext类的构造函数,通过DbContext类的构造函数创建数据库连接
14         /// 2、DbContext类的构造函数里面的参数是数据库连接字符串,通过该连接字符串去创建数据库
15         /// </summary>
16         public Context()
17             : base("name=FirstCodeFirstApp")
18         { }
19
20         //2、定义数据集合:用于创建表
21         public DbSet<Category> Categorys { get; set; }
22
23         public DbSet<Product> Products { get; set; }
24     }
25 }

在这里,DbContext是所有基于EF的上下文基类,通过它可以访问到数据库中的所有表。上面的代码中调用了父类的构造函数,并且传入了一个键值对,键是name,值是CodeFirstApp,这个键值对是定义在应用程序的配置文件中的,取决于你的应用程序类型,可能是app.config或者web.config。在我们的控制台应用程序中就是app.config。

在app.config文件的configuration节点下(不要在第一个节点下,否则会报错)添加:

1 <connectionStrings>
2     <add name="CodeFirstApp" connectionString="Server=.;Database=CodeFirstApp;User Id=sa;Password=test" providerName="System.Data.SqlClient"/>
3 </connectionStrings>

3、使用EF提供的API访问数据库来创建数据库

 1 using CodeFirstAppDemo.EFDbContext;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6
 7 namespace CodeFirstAppDemo
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             // 使用数据库上下文Context
14             using (var context = new Context())
15             {
16                  // 如果数据库不存在,则调用EF内置的API创建数据库
17                 if (context.Database.CreateIfNotExists())
18                 {
19                     Console.WriteLine("数据库创建成功!");
20                 }
21                 else
22                 {
23                     Console.WriteLine("数据库已存在");
24                 }
25             }
26
27             Console.ReadKey();
28         }
29     }
30 }

最后,只需要确保连接字符串没有问题就可以了。运行程序,然后打开SSMS进行确认数据库是否创建成功即可。

这时可以清楚地看到,数据库表名是自定义数据库上下文中DbSet<T>属性中T类型的复数形式。例如T类型是Product,那么生成的表名就是Products,而表中的列是数据模型的属性。此外,注意以下列的类型。EF默认将id作为了主键,string类型的ProductName在数据库中的类型是nvarchar(max),这些都是在使用EF时必须注意的命名规格。

四、执行简单的CRUD操作

1、创建记录-Create

你可以这样认为,将对象添加到集合中就相当于将数据插入到数据库相应的表中。我们使用DbSet的Add方法来实现新数据的添加,而DbContext类的SaveChanges方法会将未处理的更改提交到数据库,这是通过检测上下文中所有的对象的状态来完成的。所有的对象都驻留在上下文类的DbSet属性中。比如,例子中有一个Products属性,那么所有的产品数据都会存储到这个泛型集合属性中。数据库上下文会跟踪DbSet属性中的所有对象的状态,这些状态有这么几种:Deleted、Added、Modified和Unchanged。如果你想在一个表中插入多行数据,那么只需要添加该表对应的类的多个对象的实例即可,然后使用SaveChanges方法将更改提交到数据库,该方法是以单事务执行的。最终,所有的数据库更改都会以单个工作单元持久化。既然是事务,那么就允许将批量相关的更改作为单个操作提交,这样就保证了事务一致性和数据完整性。

修改Main方法如下:

 1 using CodeFirstAppDemo.EFDbContext;
 2 using CodeFirstAppDemo.Models;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.Linq;
 6 using System.Text;
 7
 8 namespace CodeFirstAppDemo
 9 {
10     class Program
11     {
12         static void Main(string[] args)
13         {
14             // 使用数据库上下文Context
15             using (var context = new Context())
16             {
17                  // 如果数据库不存在,则调用EF内置的API创建数据库
18                 if (context.Database.CreateIfNotExists())
19                 {
20                     Console.WriteLine("数据库创建成功!");
21                 }
22                 else
23                 {
24                     Console.WriteLine("数据库已存在");
25                 }
26
27                 #region EF 添加数据
28                 //添加数据
29                 var cate = new List<Category> {
30                    new Category{
31                     CategoryName="文学类",
32                     ProductList=new List<Product>{
33                           new Product
34                    {
35                      ProductName="百年孤独",
36                      Price=37.53m,
37                      PublicDate=new DateTime(2011,6,1)
38
39                    },
40                      new Product
41                    {
42                      ProductName="老人与海",
43                      Price=37.53m,
44                      PublicDate=new DateTime(2010,6,1)
45
46                    }
47                       }
48                    },
49                     new Category{
50                     CategoryName="计算机类",
51                     ProductList=new List<Product>{
52                           new Product
53                    {
54                     ProductName="C#高级编程第九版",
55                      Price=48.23m,
56                      PublicDate=new DateTime(2016,2,8)
57                    },
58                     new Product
59                    {
60                      ProductName="Oracle从入门到精通",
61                      Price=27.03m,
62                      PublicDate=new DateTime(2014,7,9)
63                    }
64                       }
65                    }
66
67                 };
68
69                 //将创建的集合添加到上下文中
70                 context.Categorys.AddRange(cate);
71                 //调用SaveChanges()方法,将数据插入到数据库
72                 context.SaveChanges();
73                 #endregion
74             }
75
76             Console.ReadKey();
77         }
78     }
79 }

这里需要注意两点:
1、不需要给Product.Id属性赋值,因为它对应到SQL Server表中的主键列,它的值是自动生成的,当SaveChanges执行以后,打断点就能看到返回的Product.Id已经有值了。
2、Context的实例用了using语句包装起来,这是因为DbContext实现了IDisposable接口。DbContext还包含了DbConnection的实例,该实例指向了具有特定连接字符串的数据库。在EF中合适地释放数据库连接和ADO.NET中同等重要。

2、查询记录-Retrieve
查询时也是直接通过DbSet进行查询的:

 1 using CodeFirstAppDemo.EFDbContext;
 2 using CodeFirstAppDemo.Models;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.Linq;
 6 using System.Text;
 7
 8 namespace CodeFirstAppDemo
 9 {
10     class Program
11     {
12         static void Main(string[] args)
13         {
14             // 使用数据库上下文Context
15             using (var context = new Context())
16             {
17                  // 如果数据库不存在,则调用EF内置的API创建数据库
18                 if (context.Database.CreateIfNotExists())
19                 {
20                     Console.WriteLine("数据库创建成功!");
21                 }
22                 else
23                 {
24                     Console.WriteLine("数据库已存在");
25                 }
26
27                 #region EF 2查询数据
28
29                 //查询方式1
30                 var products = from p in context.Categorys select p;
31                 foreach (var item in products)
32                 {
33                     Console.WriteLine("分类名称:" + item.CategoryName);
34                 }
35
36                 //查询方式2
37                 //延迟加载 cates里面没有数据
38                 var cates = context.Categorys;
39                 //执行迭代的时候才有数据
40                 foreach (var item in cates)
41                 {
42                     Console.WriteLine("分类名称:" + item.CategoryName);
43                 }
44                 #endregion
45             }
46
47             Console.ReadKey();
48         }
49     }
50 }

如果像下面那样打一个断点,你会看到一个结果视图,点击类似刷新的图标会看到查询的结果,这个东西道出了EF中很重要的一个概念:延迟加载。此时还没有真正查询数据库,只有当LINQ的查询结果被访问或者被枚举时才会将查询命令发送到数据库。EF是基于DbSet实现的IQueryable接口来处理延迟查询的。

3、更新记录-Update
在SQL中,更新需要执行Update命令。而在EF中,我们要找到DbSet实体集合中要更新的对象,然后修改其属性,最后调用SaveChanges方法即可。

using CodeFirstAppDemo.EFDbContext;
using CodeFirstAppDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CodeFirstAppDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 使用数据库上下文Context
            using (var context = new Context())
            {
                 // 如果数据库不存在,则调用EF内置的API创建数据库
                if (context.Database.CreateIfNotExists())
                {
                    Console.WriteLine("数据库创建成功!");
                }
                else
                {
                    Console.WriteLine("数据库已存在");
                }

                #region EF 更新数据

                var products = context.Products;
                if (products.Any())
                {
                    // 查询产品名称是“百年孤独”的产品
                    var toUpdateProduct = products.First(p => p.ProductName == "百年孤独");
                    // 修改查询出的产品名称
                    toUpdateProduct.ProductName = "唐诗三百首";
                    // 调用SaveChanges()方法保存数据
                    context.SaveChanges();
                }

                #endregion
            }

            Console.ReadKey();
        }
    }
}

这里我们使用了Any()扩展方法来判断序列中是否有元素,然后使用First()扩展方法来找到Name=="百年孤独"的元素,然后给目标对象的Name属性赋予新值,最后调用SaveChanges()方法保存数据。

4、删除记录-Delete
要删除一条数据,就要先找到这条数据.

 1 using CodeFirstAppDemo.EFDbContext;
 2 using CodeFirstAppDemo.Models;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.Data.Entity;
 6 using System.Linq;
 7 using System.Text;
 8
 9 namespace CodeFirstAppDemo
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             // 使用数据库上下文Context
16             using (var context = new Context())
17             {
18                  // 如果数据库不存在,则调用EF内置的API创建数据库
19                 if (context.Database.CreateIfNotExists())
20                 {
21                     Console.WriteLine("数据库创建成功!");
22                 }
23                 else
24                 {
25                     Console.WriteLine("数据库已存在");
26                 }
27
28                 #region EF 删除数据
29
30                 var products = context.Products;
31                 // 先根据ProductName找到要删除的元素
32                 var toDeleteProduct = context.Products.Single(p => p.ProductName == "唐诗三百首");
33                 if (toDeleteProduct != null)
34                 {
35                 // 方式1:使用Remove()方法移除
36                 context.Products.Remove(toDeleteProduct);
37                 // 方式2:更改数据的状态
38                 context.Entry(toDeleteProduct).State = EntityState.Deleted;
39                 // 最后持久化到数据库
40                 context.SaveChanges();
41
42                 #endregion
43             }
44
45             Console.ReadKey();
46         }
47     }
48 }
时间: 2024-10-27 17:09:47

EF应用一:Code First模式的相关文章

EF 下的code fist 模式编程

EF 分两种模式 codefirst(就是不知道数据是啥,也没有数据库)  和 database fist (数据已经设计好了) 首先打开vs  新建一个项目 创建一个控制台程序 然后 新建一个Teacher 类 public class Teacher { public int TeacherId { get; set; } public string Name { get; set; } public string Country { get; set; } public string De

MVC+EF 理解和实现仓储模式和工作单元模式

MVC+EF 理解和实现仓储模式和工作单元模式 原文:Understanding Repository and Unit of Work Pattern and Implementing Generic Repository in ASP.NET MVC using Entity Framework 文章介绍 在这篇文章中,我们试着来理解Repository(下文简称仓储)和Unit of Work(下文简称工作单元)模式.同时我们使用ASP.NET MVC和Entity Framework 搭

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有所区

Code First模式学习

开篇            因为前段时间一直学习mvc,当然小菜也知道在mvc中都主推使用EF模式来对数据库的访问,在学习mvc的过程中使用EF也遇到了很多问题,在这过程中也迷迷糊糊的一知半解,索性就决定从头开始学习使用EF,当然在EF中有三种模式的,Model First.Database First,当然这次主要是以学习Code First模式为准了. 新建项目 使用NuGet联机添加了EntityFreamework 该EntityFreamwork的版本是6.0.0.0 添加Model

Entity Framework应用:Code First模式数据迁移的基本用法

使用Entity Framework的Code First模式在进行数据迁移的时候会遇到一些问题,熟记一些常用的命令很重要,下面整理出了数据迁移时常用的一些命令. 一.模型设计 EF默认使用id字段作为主键,如果没有,则需要指定主键. 二.数据迁移基本命令和常用参数 1.安装Entity Framework a.使用命令安装:visual studio工具栏->工具->NuGet 程序包管理器->程序包管理器控制台 输入命令:Install-Package EntityFramework

EF框架的三种模式

Database First就是先建数据库或使用已有的数据库.然后在vs中添加ADO.Net实体数据模型,设置连接并且选择需要的数据库和表.它是以数据库设计为基础的,并根据数据库自动生成实体数据模型,从而驱动整个开发流程.除生成实体模型和自跟踪实现模型,还支持生成轻型DbContext.这种模式的好处是使用简单,容易上手.比较适合于采用已经存在的数据库进行开发.既通过简单的方式实现了,又重用了数据库. ModelFirst开发模式是指从建立实体数据模型入手,并依据模型生成数据库,从而驱动整个开发

使用 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型 .      所以解决的办法就是修改数据库字段型 ,一般情况下,

EF6 Code First 模式更新数据库架构

定义好实体类和上下文类 在 Package Manager Console 输入以下命令 1.Enable-Migrations 启用数据迁移功能,该命令通常会在项目根目录下生成 Migrations 文件夹,文件夹内通常会有两个文件 201408020650593_InitialCreate.cs -- 迁移前的数据结构,前半段为时间戳 Configuration.cs -- 相关配置,是否需要自动迁移等,默认为 false 2.Add-Migration 增加迁移点,输入该命令后会要求你输入

使用Code First模式开发如何更新数据库(转载)

原文: http://blog.bossma.cn/csharp/code-first-how-to-upgrade-database/ Code First模式 使用Code First模式开发数据库时,首先编写实体类,继承DbContext创建数据操作类,然后在这个基础上编写自己的业务处理程序,然后在系统运行前配置数据连接,当系统第一次运行时会自动创建数据库(当前版本中使用DropCreateDatabaseIfModelChanges策略时,系统第一次运行时如果数据库已经存在则会抛出异常,