运维开发网

使用CodeFirst模式管理存储过程

运维开发网 https://www.qedev.com 2022-08-18 19:57 出处:网络
本文详细讲解了EntityFramework使用CodeFirst模式管理存储过程的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

本文详细讲解了EntityFramework使用CodeFirst模式管理存储过程的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

在EF中使用存储过程与使用视图非常相似。一般情况下,对数据库对象使用两种方法:SqlQuery和ExecuteSqlCommand。为了从存储过程中读取许多数据行,我们只需要定义一个类,并将所有检索到的数据行具体化到该类的实例集合中。例如,从以下存储过程中读取数据:

CREATE PROCEDURE [dbo].[SelectBooks]@BookTypeName AS NVARCHAR(10)ASBEGINselect B.Name,B.Author,B.PublicationDate,T.BookTypeName from Books as Bjoin BookTypes as T on B.BookTypeId=T.BookTypeId where T.BookTypeName=@BookTypeNameEND1、定义实体类

Book实体类定义如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeFirstProcedureApp.Model{ public class Book { public int Id { get; set; } public string Name { get; set; } public string Author { get; set; } public DateTime PublicationDate { get; set; } public Virtual BookType BookType { get; set; } }}

BookType实体类定义如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeFirstProcedureApp.Model{ public class BookType { public BookType() { Books = new HashSetlt;Bookgt;(); } public int BookTypeId { get; set; } public string BookTypeName { get; set; } public Virtual ICollectionlt;Bookgt; Books { get; set; } }}2、定义与存储过程结果匹配的实体类using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeFirstProcedureApp.Model{ public class BookFromProcedure { public string Name { get; set; } public string Author { get; set; } public DateTime PublicationDate { get; set; } public string BookTypeName { get; set; } }}

注意:类的属性名必须与存储过程中定义的列名一致。

3、创建种子初始化器类using CodeFirstProcedureApp.Model;using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeFirstProcedureApp.EF{ public class Initializer : DropCreateDatabaseIfModelChangeslt;EFDbContextgt; { protected override void Seed(EFDbContext context) { // 创建初始化数据 BookType bookType = new BookType() { BookTypeName = "文学小说", Books = new Listlt;Bookgt; { new Book(){Name="人间失格",Author="太宰治",PublicationDate=DateTime.Parse("2015-08-01")}, new Book(){Name="解忧杂货店",Author="东野圭吾",PublicationDate=DateTime.Parse("2014-05-01")}, new Book(){Name="追风筝的人",Author="卡勒德胡赛尼",PublicationDate=DateTime.Parse("2006-08-01")}, new Book(){Name="百年孤独",Author="加西亚马尔克斯",PublicationDate=DateTime.Parse("2011-06-01")}, new Book(){Name="霍乱时期的爱情",Author="加西亚马尔克斯",PublicationDate=DateTime.Parse("2015-06-01")} } }; BookType bookType2 = new BookType() { BookTypeName = "科学", Books = new Listlt;Bookgt; { new Book(){Name="人类简史",Author="尤瓦尔赫拉利",PublicationDate=DateTime.Parse("2017-01-01")} } }; context.BookTypes.Add(bookType); context.BookTypes.Add(bookType2); base.Seed(context); } }}4、定义数据上下文类using CodeFirstProcedureApp.Model;using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CodeFirstProcedureApp.EF{ public class EFDbContext :DbContext { public EFDbContext() : base("name=AppConnection") { Database.SetInitializer(new Initializer()); } // 添加到数据上下文中 public DbSetlt;Bookgt; Books { get; set; } public DbSetlt;BookTypegt; BookTypes { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 配置表名和主键 modelBuilder.Entitylt;Bookgt;().ToTable("Books").HasKey(p =gt; p.Id); modelBuilder.Entitylt;BookTypegt;().ToTable("BookTypes").HasKey(p =gt; p.BookTypeId); // 设置实体关系 // BookType和 Books 一对多关系 外键:BookTypeId modelBuilder.Entitylt;BookTypegt;().HasMany(p =gt; p.Books).WithRequired(t =gt; t.BookType) .Map(m =gt; { m.MapKey("BookTypeId"); }); base.OnModelCreating(modelBuilder); } }}5、运行程序

使用SQL语句创建存储过程:

var createSql = @"CREATE PROCEDURE [dbo].[SelectBooks] @BookTypeName AS NVARCHAR(10) AS BEGIN select B.Name,B.Author,B.PublicationDate,T.BookTypeName from Books as B join BookTypes as T on B.BookTypeId=T.BookTypeId where T.BookTypeName=@BookTypeName END";context.Database.ExecuteSqlCommand(createSql);

查看数据库:


调用存储过程来查询数据。

注意:在使用存储过程之前,必须先执行存储过程中的存储过程,或者使用上述程序生成存储过程。

var sql = "SelectBooks {0}";var books = context.Database.SqlQuerylt;BookFromProceduregt;(sql, "文学小说");books.ToList().ForEach(p =gt;{ Console.WriteLine("BookName:" + p.Name + " Author:" + p.Author + " BookTypeName:" + p.BookTypeName + " PublicationDate:" + p.PublicationDate);});

在上面的代码中,我们已经确定了使用哪个类来读取查询结果。在创建SQL语句时,我们还为存储过程的参数提供了一个格式化的占位符。当调用SqlQuery时,我们为该参数提供一个值。如果要提供多个参数,必须用逗号分隔多个格式占位符,并为SqlQuery提供一个值数组。我们也可以使用表值函数来代替存储过程。存储过程的执行结果如下:


6、执行无返回值的存储过程

另一个用例是,如果存储过程没有任何返回值,但只对数据库中的一个或多个表执行命令。存储过程做多少事情并不重要,但它不返回任何数据。例如,以下存储过程仅更新一些数据:

CREATE PROCEDURE UpdateBooks@name AS NVARCHAR(60),@id as intAS BEGINUPDATE Books SET Name=@nameWHERE Id=@idEND

要先执行数据库中的存储过程,然后调用存储过程,我们使用ExecuteSqlCommand()方法。该方法将返回受存储过程或任何其他SQL语句影响的行数。如果对这个返回值不感兴趣,可以忽略这个返回值。

var sql = "UpdateBooks @name,@id";SqlParameter[] para = new SqlParameter[]{ new SqlParameter("@id",1d), new SqlParameter("@name","人间失败"),};var book = context.Books.Where(p =gt; p.Id == 1);Console.WriteLine("执行存储过程前的数据为:");foreach (var item in book){ Console.WriteLine(item.Name + "\t" + item.Author + "\t" + item.PublicationDate);}var rowsAffected = context.Database.ExecuteSqlCommand(sql, para);Console.WriteLine("影响的行数为{0}条", rowsAffected);Console.WriteLine("执行存储过程之后的数据为:");var books = context.Books.Where(p =gt; p.Id == 1);foreach (var item in books){ Console.WriteLine(item.Name + "\t" + item.Author + "\t" + item.PublicationDate);}

上面的代码为存储过程提供了两个参数:一个是Name,另一个是id。这里需要注意:我们必须按照存储过程中定义的顺序传入相应的值,它们将作为参数数组传入ExecuteSqlCommand。执行结果如下:


在很大程度上,EF减少了对存储过程的需求。然而,仍然有许多使用它们的理由。这些原因包括安全标准、遗留数据库或效率问题。比如你需要一次操作更新几千条数据,然后通过EF检索;如果每次更新一行,然后保存那些实例,效率就很低了。最后,即使使用SqlQuery()方法调用存储过程,也可以更新数据。

注意:开发人员可以执行任何SQL语句,只需将上述SqlQuery或ExecuteSqlCommand方法中的存储过程名改为要执行的SQL语句即可。

示例代码下载地址:单击此处下载

这就是本文关于实体框架使用代码优先模式管理存储过程的全部内容。

0

精彩评论

暂无评论...
验证码 换一张
取 消