在这里, 我们将尝试去学习一下 .net core EF Core 中调用存储过程.
我们知道, EF Core 是不支持直接调用存储过程的, 那它又提供了什么样的方式去执行存储过程呢? 有如下方法:
1,FromSql, 官方文档
DbSet<TEntity>.FromSql()
2, 执行 SQl 命令
DbContext.Database.ExecuteSqlCommand()
但是, 这两种方式都有局限性:
1,FromSql 方式的结果一定要是实体类型, 就是数据库表映射的模型. 这意味着, 执行存储过程返回的结果一定是跟数据库表相关的所有字段;
2,FromSql 方式的结果不能有关联关系数据. 这就相当于不能 join , 也返回不了 join 的关联表的数据.
3,ExecuteSqlCommand 执行插入, 更新跟删除的存储过程不能直接映射到实体(EF Core 不支持嘛, 在讲 EF 跟 EF Core 的区别时已经很清晰了), 所以, CUD 方法不能直接调用 SaveChanges 方法.
我们来试试演示一下:
(1)准备一个存储过程, 一般为了方便, 直接就是 DB-First, 执行以下的 SQL 脚本就 OK 了
- USE [Library]
- GO
- SET ANSI_NULLS ON
- GO
- SET QUOTED_IDENTIFIER ON
- GO
- CREATE PROCEDURE [dbo].[proc_getbooks]
- @name nvarchar(50)
- AS
- BEGIN
- SET NOCOUNT ON;
- select * from books where name like @name +'%'
- END
- GO
当创建好了这个有传参的有返回结果的存储过程的时候, 数据库在可编程性下就有一个存储过程了(这个数据库是我专门用来做 demo 的)
(2)用 FromSql 调用存储过程, 由上面就可以知道它是 DbSet 的方法, 而 DbSet 是可以执行原生的 sql 语句去查询底层的数据库. 同样, 使用 DbSet 可以执行存储过程, 从而返回实体类型, 但就是具有上面所说的局限性罢了.
- // 用 FromSql 调存储过程
- var name = "C";
- var books = _context.Books
- .FromSql($"proc_getbooks {name}")
- .ToList();
- //or 使用 exec 关键字调用存储过程
- //var books = _context.Books.FromSql($"exec proc_getbooks {name}").ToList();
- //or 使用 SqlParameter 实例进行参数的插入
- //var param = new SqlParameter()
- //{
- // ParameterName = "@name",
- // SqlDbType = System.Data.SqlDbType.NVarChar,
- // Direction = System.Data.ParameterDirection.Input,
- // Size = 50,
- // Value = name
- //};
- //or 使用 @p0 代表第一个参数, 则 @p1 就代表第二个参数等以此类推
- //var books = _context.Books.FromSql("proc_getbooks @p0", name).ToList();
同样, 在这里值得一提的是, 当我们多次调用同一个存储过程, 传递同样的参数的时候, 比如像下面:
- // 用 FromSql 多次调同一个存储过程
- var name = "C";
- var list1 = _context.Books.FromSql($"proc_getbooks {name}").ToList();
- var list2 = _context.Books.FromSql($"proc_getbooks {name}").ToList();
- var list3 = _context.Books.FromSql($"proc_getbooks {name}").ToList();
所有的实体默认 (可以设置) 都会被 DbContext 进行跟踪. 如果你执行同样的存储过程, 传同样的参数的时候, 进行多次执行的时候, 相当于执行同样的 sql 语句多次, 但返回的结果确认一样的, 根据 DbContext 的跟踪, 直接就获取缓存进行返回结果了. 就是说, 存储过程会被调用多次, 但只查了一次数据库, 其他的在缓存里拿数据.
(3)用 ExecuteSqlCommand 调用存储过程, 这个跟 EF 是一个毛样的, 由于要测试的话, 还要创建一个存储过程, 因为这个执行查询没有意义, 如果你看它的返回的话, 都是 int 类型, 而且返回结果都是影响的行数.
看看源码:
其实 ExecuteSqlCommand 最终是调用 ExecuteNonQuery, 就是执行非查询的语句, 返回影响的行数, 也验证了刚才所说的.
扯远了, 那么再创建一个存储过程吧
- CREATE PROCEDURE [dbo].[proc_createbook]
- @name Varchar(50),
- @author Varchar(50),
- @cateid int
- AS
- BEGIN
- SET NOCOUNT ON;
- Insert into books(
- [name]
- ,[author]
- ,[createtime]
- ,[isdel]
- ,[cateid]
- )
- Values (@name, @author,GETDATE(),0,@cateid)
- END
- GO
创建后
来调用以下试试:
- // 用 ExecuteSqlCommand 调存储过程, 用 parameters: new[] {}也是可以的
- var name = "C# 高级进阶";
- var author = "-";
- var cateid = 1;
- _context.Database.ExecuteSqlCommand("proc_createbook @p0,@p1,@p2", name, author, cateid);
执行结果:
OK, 是可以执行成功的.
到这里先完成第一部分先, 接下来就做调用存储过程的扩展, 因为单靠这两种调用方式, 我们是不会满足的!
来源: https://www.cnblogs.com/Vam8023/p/10785854.html