EFCore执行Sql语句的方法:FromSql与ExecuteSqlCommand
前言
在EFCore中执行Sql语句的方法为:FromSql与ExecuteSqlCommand;在EF6中的为SqlQuery与ExecuteSqlCommand,而FromSql和SqlQuery有很大区别,FromSql返回值为IQueryable,因此为延迟加载的,可以与Linq扩展方法配合使用,但是有不少的坑(EFCore版本为1.1.0),直接执行Sql语句的建议不要使用FromSql,但是EFCore中并没有提供SqlQuery方法,因此下面会贴出SqlQuery的实现代码供大家参考,以便在EFCore中能使用。
FromSql和ExecuteSqlCommand的使用
测试时使用了SqlServer2008和SqlServer Profiler进行Sql语句捕捉,EFCore的版本为1.1.0。
测试的Entity Model与DbContext
public class MSSqlDBContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"data source=localhost;initial catalog=TestDB;Integrated Security=True;");
}
public DbSet<Person> Person { get; set; }
public DbSet<Address> Address { get; set; }
} [Table(nameof(Person))]
public class Person
{
public int id { get; set; }
public string name { get; set; }
[Column(TypeName = "datetime")]
public DateTime? birthday { get; set; }
public int? addrid { get; set; }
} [Table(nameof(Address))]
public class Address
{
public int id { get; set; }
public string fullAddress { get; set; }
public double? lat { get; set; }
public double? lon { get; set; }
}
ExecuteSqlCommand
EFCore的ExecuteSqlCommand和EF6的一样,执行非查询的Sql语句:
var db = new MSSqlDBContext();
db.Database.ExecuteSqlCommand($"update {nameof(Person)} set name=@name where id=@id", new[]
{
new SqlParameter("name", "tom1"),
new SqlParameter("id", ),
});
FromSql
官方参考文档:https://docs.microsoft.com/en-us/ef/core/querying/raw-sql
简单使用
var db = new MSSqlDBContext();
var name = "tom";
var list = db.Set<Person>().FromSql($"select * from {nameof(Person)} where {nameof(name)}=@{nameof(name)} ",
new SqlParameter(nameof(name), name)).ToList();
生成的Sql:
exec sp_executesql N'select * from Person where name=@name
',N'@name nvarchar(3)',@name=N'tom'
注意:
默认生成的为Person的Model,如果Select获取的字段中不包含Person中的某字段就会抛异常了,例如:下面的语句只获取name字段,并没有包含Person的其他字段,那么抛异常:The required column 'id' was not present in the results of a 'FromSql' operation.
db.Set<Person>().FromSql($"select name from {nameof(Person)} ").ToList();
那么改为:
db.Set<Person>().Select(l => l.name).FromSql($"select name from {nameof(Person)} ").ToList();
执行存储过程
var db = new MSSqlDBContext();
db.Set<Person>().FromSql("exec testproc @id", new SqlParameter("id", )).ToList();
生成的Sql:
exec sp_executesql N'exec testproc @id
',N'@id int',@id=1
与Linq扩展方法配合使用
var db = new MSSqlDBContext();
db.Set<Person>().FromSql($"select * from {nameof(Person)} where name=@name ", new SqlParameter("@name", "tom"))
.Select(l => new { l.name, l.birthday }).ToList();
生成的Sql:
exec sp_executesql N'SELECT [l].[name], [l].[birthday]
FROM (
select * from Person where name=@name
) AS [l]',N'@name nvarchar(3)',@name=N'tom'
inner join + order by
var db = new MSSqlDBContext();
(from p in db.Set<Person>().FromSql($"select * from {nameof(Person)} ")
join a in db.Set<Address>().Where(l => true)
on p.addrid equals a.id
select new { p.id, p.name, a.fullAddress }).OrderBy(l => l.id).ToList();
生成的Sql:
SELECT [p].[id], [p].[name], [t].[fullAddress]
FROM (
select * from Person
) AS [p]
INNER JOIN (
SELECT [l0].*
FROM [Address] AS [l0]
) AS [t] ON [p].[addrid] = [t].[id]
ORDER BY [p].[id]
left join + order by
var db = new MSSqlDBContext();
(from p in db.Set<Person>().FromSql($"select * from {nameof(Person)} ")
join a in db.Set<Address>().Where(l => true)
on p.addrid equals a.id into alist
from a in alist.DefaultIfEmpty()
select new { p.id, p.name, fullAddress = a == null ? null : a.fullAddress }).OrderBy(l => l.id).ToList();
生成的Sql:(生成的Sql很有问题,order by后面多了[p].[addrid],而且生成的select的字段也是多了)
SELECT [p].[id], [p].[addrid], [p].[birthday], [p].[name], [t].[id], [t].[fullAddress], [t].[lat], [t].[lon]
FROM (
select * from Person
) AS [p]
LEFT JOIN (
SELECT [l0].[id], [l0].[fullAddress], [l0].[lat], [l0].[lon]
FROM [Address] AS [l0]
) AS [t] ON [p].[addrid] = [t].[id]
ORDER BY [p].[id], [p].[addrid]
将FromSql换成Where扩展方法试试:
(from p in db.Set<Person>().Where(l => true)
join a in db.Set<Address>().Where(l => true)
on p.addrid equals a.id into alist
from a in alist.DefaultIfEmpty()
select new { p.id, p.name, fullAddress = a == null ? null : a.fullAddress }).OrderBy(l => l.id).ToList();
EFCore生成的Sql(order by后面还是多了[addrid],select的字段也是多了):
SELECT [l].[id], [l].[addrid], [l].[birthday], [l].[name], [t].[id], [t].[fullAddress], [t].[lat], [t].[lon]
FROM [Person] AS [l]
LEFT JOIN (
SELECT [l1].[id], [l1].[fullAddress], [l1].[lat], [l1].[lon]
FROM [Address] AS [l1]
) AS [t] ON [l].[addrid] = [t].[id]
ORDER BY [l].[id], [l].[addrid]
而在EF6中生成的Sql,比EFCore的生成好多了:
SELECT
[Project1].[id] AS [id],
[Project1].[name] AS [name],
[Project1].[C1] AS [C1]
FROM ( SELECT
[Extent1].[id] AS [id],
[Extent1].[name] AS [name],
CASE WHEN ([Extent2].[id] IS NULL) THEN CAST(NULL AS varchar(1)) ELSE [Extent2].[fullAddress] END AS [C1]
FROM [dbo].[Person] AS [Extent1]
LEFT OUTER JOIN [dbo].[Address] AS [Extent2] ON [Extent1].[addrid] = [Extent2].[id]
) AS [Project1]
ORDER BY [Project1].[id] ASC
结果说明
FromSql不能代替原来EF6的SqlQuery使用,而且结合Linq扩展方法使用的时候生成的Sql会存在一些问题(EFCore版本为:1.1.0),那么为了能在EFCore中执行Sql查询语句,下面提供对SqlQuery方法的实现。
SqlQuery的实现
public static IList<T> SqlQuery<T>(DbContext db, string sql, params object[] parameters)
where T : new()
{
//注意:不要对GetDbConnection获取到的conn进行using或者调用Dispose,否则DbContext后续不能再进行使用了,会抛异常
var conn = db.Database.GetDbConnection();
try
{
conn.Open();
using (var command = conn.CreateCommand())
{
command.CommandText = sql;
command.Parameters.AddRange(parameters);
var propts = typeof(T).GetProperties();
var rtnList = new List<T>();
T model;
object val;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
model = new T();
foreach (var l in propts)
{
val = reader[l.Name];
if (val == DBNull.Value)
{
l.SetValue(model, null);
}
else
{
l.SetValue(model, val);
}
}
rtnList.Add(model);
}
}
return rtnList;
}
}
finally
{
conn.Close();
}
}
使用:
var db = new MSSqlDBContext();
string name = "tom";
var list = SqlQuery<PAModel>(db,
$" select p.id, p.name, a.fullAddress, a.lat, a.lon " +
$" from ( select * from {nameof(Person)} where {nameof(name)}=@{nameof(name)} ) as p " +
$" left join {nameof(Address)} as a on p.addrid = a.id ",
new[] { new SqlParameter(nameof(name), name) });
生成的Sql:
exec sp_executesql N' select p.id, p.name, a.fullAddress, a.lat, a.lon from ( select * from Person where name=@name ) as p left join Address as a on p.addrid = a.id ',N'@name nvarchar(3)',@name=N'tom'
EFCore执行Sql语句的方法:FromSql与ExecuteSqlCommand的更多相关文章
- 两种查看EFCore生成Sql语句的方法
一.利用反射生成查询语句 该方法转载自:https://jhrs.com/2019/28488.html (略有修改) using Microsoft.EntityFrameworkCore.Quer ...
- SQL Server 定时执行SQL语句的方法
SQL SERVER 定时任务,你可以启动一下.不过要想更加直观的控制,直接写一个程序,定时执行你的存储过程. 1.设置“SQL Server 代理”(SQL Server Agent)服务随系统启动 ...
- Hibernate执行SQL语句实现查询修改功能!
今天玩Hibernate时突然就想写写SQL语句查询... DAO : //查询 public List<?> createSqlQueryList(final String queryS ...
- nhibernate中执行SQL语句
在有些时候,可能需要直接执行SQL语句.存储过程等,但nhibernate并没有提供一种让我们执行SQL语句的方法,不过可以通过一些间接的方法来实现. 下面给出一个在nhibernate中执行SQL语 ...
- ABP 执行sql语句
由于业务繁琐,用EF比较麻烦,需要用到sql语句,然后网上找了很久,找到的例子都是老版本的,新版本有先声明已经去掉,不能用了 在这里做个小记 首先注入实例 private readonly IDbCo ...
- EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery
一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...
- PLSQL执行sql语句输出的中文是???之解决方法和步骤
方法/步骤 1 登陆plsql,执行sql语句,输出的中文标题显示成问号????:条件包含中文,则无数据输出 步骤阅读 2 输入sql语句select * from V$NLS_PARAMETERS查 ...
- Shell脚本中执行sql语句操作mysql的5种方法【转】
对于自动化运维,诸如备份恢复之类的,DBA经常需要将SQL语句封装到shell脚本.本文描述了在Linux环境下mysql数据库中,shell脚本下调用sql语句的几种方法,供大家参考.对于脚本输出的 ...
- 解决乱码的方法是,在执行SQL语句之前,将MySQL以下三个系统参数设置为与服务器字符集character-set-server相同的字符集
character-set-server/default-character-set:服务器字符集,默认情况下所采用的. character-set-database:数据库字符集. characte ...
随机推荐
- iOS并发编程笔记【转】
线程 使用Instruments的CPU strategy view查看代码如何在多核CPU中执行.创建线程可以使用POSIX 线程API,或者NSThread(封装POSIX 线程API).下面是并 ...
- PostgreSQL 与 MySQL 相比,优势何在?
一. PostgreSQL 的稳定性极强, Innodb 等引擎在崩溃.断电之类的灾难场景下抗打击能力有了长足进步,然而很多 MySQL 用户都遇到过Server级的数据库丢失的场景——mysql系统 ...
- 简单明了区分escape、encodeURI和encodeURIComponent
一.前言 讲这3个方法区别的文章太多了,但是大部分写的都很绕.本文试图从实践角度去讲这3个方法. 二.escape和它们不是同一类 简单来说,escape是对字符串(string)进行编码(而另外两种 ...
- Python黑帽编程3.0 第三章 网络接口层攻击基础知识
3.0 第三章 网络接口层攻击基础知识 首先还是要提醒各位同学,在学习本章之前,请认真的学习TCP/IP体系结构的相关知识,本系列教程在这方面只会浅尝辄止. 本节简单概述下OSI七层模型和TCP/IP ...
- 《CLR.via.C#第三版》第二部分第10,11章节读书笔记(五)
第10章是对 属性 做阐述 属性本质上是方法 匿名类型的使用: }; Console.WriteLine("Name={0},Year={1}",o1.Name,o1.Year); ...
- [ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject
本人博客已转移至:http://www.exblr.com/liam 为什么需要依赖注入 在[ASP.NET MVC 小牛之路]系列的理解MVC模式文章中,我们提到MVC的一个重要特征是关注点分离( ...
- KnockoutJS 3.X API 第八章 映射(mapping)插件
Knockout旨在允许您将任意JavaScript对象用作视图模型. 只要一些视图模型的属性是observables,您可以使用KO将它们绑定到您的UI,并且UI将在可观察属性更改时自动更新. 大多 ...
- Adobe Photoshop CC 打开时报错~配置错误:请卸载并重新安装该产品
后期会在博客首发更新:http://dnt.dkill.net 异常处理汇总-开发工具 http://www.cnblogs.com/dunitian/p/4522988.html 个人估计,要么安 ...
- 【已解决】WinPhone模拟器报错:模拟器没法确定来宾虚拟机通信的主机ID地址。某些功能已被禁用
先看警告 再看错误信息 计算机管理打不开就==>Win+R ==>compmgmt.msc 发现,dnt在管理员权限组里面,也在Hyper-V权限组里面 看看Hyper-V的驱动有木有被禁 ...
- 【Win10 应用开发】从前台应用触发后台任务
有关后台任务的使用,估计大伙伴们不会陌生,而且老周曾经在某文中也简单讲述过.说到后台任务,老周想到了一个问题:有人问,后台任务一定要独立写到一个Runtime组件中吗,能不能写到主项目的代码中? 老周 ...