zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    C++ 临时对象
    【转】C++ static关键字
    python读写文件
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
    Debian下的crontab保存
    Innodb后台线程
    查看当前数据库支持哪些存储引擎
    ERROR: No query specified
    WARNING: The host 'r6' could not be looked up with /usr/local/mysql/bin/resolveip.
    mysql_install_db 运行结果
  • 原文地址:https://www.cnblogs.com/dotnet261010/p/7119351.html
Copyright © 2011-2022 走看看