在ABP中通过EF直接执行原生Sql的解决方案
一般情况下,使用EF中的查询语法和方法语法可以帮助我们完成绝大部分业务,但是也有特殊的情况需要直接执行Sql语句。比如,我们的业务过于复杂繁琐,或是有些业务使用EF操作时比较复杂,但是使用Sql时会很简单等等。
今天做项目的时候,就由于使用EF来处理逻辑时格外棘手,最终选择了直接执行Sql语句,下面说说具体的业务。
一共关系到三张表,分别是Operators(运营商表),Orders(订单表)和DeviceCoinsRecords(设备投币记录表),相应表的定义已经截图如下,就不在这里编写代码了。Operators里放运营商的数据信息,Orders是手机端扫码下单时产生的订单数据,DeviceCoinsRecords是向机器设备投币时产生的数据。
用下面的一张图解释一下:

下面是三张表的结构:



三张表之间的关联关系是:Orders和和DeviceCoinsRecords通过OperatorId关联Operators表的Id主键。
要实现的业务是:
Sql语句表达:
SELECT ROW_NUMBER() OVER(ORDER BY Id ) AS RowId,Id,Name,AllocateRatio,
(SELECT SUM(PayFee) FROM dbo.Orders WHERE Status NOT IN(0,3,4) AND OperatorID=dbo.Operators.Id AND YEAR(OrderDate)=@Year1 AND MONTH(OrderDate)=@Month1) AS TotalScanCode,
(SELECT SUM(TheDayMoney) FROM dbo.DeviceCoinsRecords WHERE dbo.DeviceCoinsRecords.OperatorID=dbo.Operators.Id AND Year=@Year2 AND Month=@Month2) AS TotalCoinsCast
FROM dbo.Operators
视图表达:

自然语言表达:
汇总运营商的年度和月度报表,也可选择具体的运营商和年月进行汇总。
一开始我是拒绝在EF中使用SQL查询的,但是花了好长时间,实在是找不到可以替代以上sql的linq语句或者Lambda方法语法,有哪位能写出来的,欢迎挑战一下,但是写出来的很复杂的话,也没这个必要了。
下面说说具体的实现【首先要声明的是我使用的是ABP框架】。
1.在核心层(Core层)的IRepositories文件下创建一个接口IOperatorReportRepository

2.该接口的定义如下代码所示:
public interface IOperatorReportRepository:IRepository<Operators>
{
Task<IEnumerable<OperatorYearOrMonthReport>> QueryMonthReports(int year, int month, int operatorId);
Task<IEnumerable<OperatorYearOrMonthReport>> QueryYearReports(int year, int operatorId);
}
3.实现接口代码:
public class OperatorReportReposiroty:ChargeStationRepositoryBase<Operators>,IOperatorReportRepository
{
public OperatorReportReposiroty(IDbContextProvider<ChargeStationDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<IEnumerable<OperatorYearOrMonthReport>> QueryMonthReports(int year, int month,int operatorId=0)
{
string whereClause = string.Empty;
if (operatorId>0)
{
whereClause += string.Format(" where Id={0} ",operatorId);
}
string sql = string.Format(@"
SELECT ROW_NUMBER() OVER(ORDER BY Id ) AS RowId,Id,Name,AllocateRatio,
(SELECT SUM(PayFee) FROM dbo.Orders WHERE Status NOT IN(0,3,4) AND OperatorID=dbo.Operators.Id AND YEAR(OrderDate)=@Year1 AND MONTH(OrderDate)=@Month1) AS TotalScanCode,
(SELECT SUM(TheDayMoney) FROM dbo.DeviceCoinsRecords WHERE dbo.DeviceCoinsRecords.OperatorID=dbo.Operators.Id AND Year=@Year2 AND Month=@Month2) AS TotalCoinsCast
FROM dbo.Operators {0}", whereClause);
return await Context.Database.SqlQuery<OperatorYearOrMonthReport>(sql,
new SqlParameter("@Year1", year),
new SqlParameter("@Month1", month),
new SqlParameter("@Year2", year),
new SqlParameter("@Month2", month)).ToListAsync();
}
public async Task<IEnumerable<OperatorYearOrMonthReport>> QueryYearReports(int year, int operatorId = 0)
{
string whereClause = string.Empty;
if (operatorId>0)
{
whereClause += string.Format(" where Id={0} ", operatorId);
}
string sql = string.Format(@"
SELECT ROW_NUMBER() OVER(ORDER BY Id )AS RowId,Id,Name,AllocateRatio,
(SELECT SUM(PayFee) FROM dbo.Orders WHERE Status NOT IN(0,3,4) AND OperatorID=dbo.Operators.Id AND YEAR(OrderDate)=@Year3) AS TotalScanCode,
(SELECT SUM(TheDayMoney) FROM dbo.DeviceCoinsRecords WHERE dbo.DeviceCoinsRecords.OperatorID=dbo.Operators.Id AND Year=@Year4) AS TotalCoinsCast
FROM dbo.Operators {0}", whereClause);
return await Context.Database.SqlQuery<OperatorYearOrMonthReport>(sql,
new SqlParameter("@Year3", year),
new SqlParameter("@Year4", year)).ToListAsync();
}
}
这里有点意思的是,如果SqlQuery的后面没有ToList()或者ToListAsync(),那么你会收获一个奇妙的礼物!你可以试试看!
4.在应用服务层调用
public async Task<PagedResultOutput<GetOperatorReportsOutput>> GetOperatorReports(GetOperatorReportsInput input)
{
int operatorId = string.IsNullOrEmpty(input.Code)
? 0 : _operatorRepository.GetAll().Single(o => o.Code == input.Code).Id;
IEnumerable<OperatorYearOrMonthReport> operatorMonthReports;
if (input.Year.HasValue && input.Month.HasValue)
{
operatorMonthReports =await _operatorReportRepository.QueryMonthReports(input.Year.Value,input.Month.Value,operatorId);
}else if (input.Year.HasValue)
{
operatorMonthReports =await _operatorReportRepository.QueryYearReports(input.Year.Value,operatorId);
}
else
{
if (input.IsThisYear)
{
operatorMonthReports = await _operatorReportRepository.QueryYearReports(DateTime.Now.Year,operatorId);
}
else
{
operatorMonthReports =await _operatorReportRepository.QueryMonthReports(DateTime.Now.Year,DateTime.Now.Month,operatorId);
}
}
var totalCount = operatorMonthReports.Count();
var operatorReportOutputList = operatorMonthReports.MapTo<List<GetOperatorReportsOutput>>();
return new PagedResultOutput<GetOperatorReportsOutput>(totalCount, operatorReportOutputList);
}
好了,这次主要记录一下在EF中如何直接调用Sql语句的用法,以后有机会再说说关于在EF中存储过程(包括输出参数的情况)的调用。
在ABP中通过EF直接执行原生Sql的解决方案的更多相关文章
- asp.net EF框架执行原生SQL语句
1.执行无参数sql: string sql = "select * from IntegralInfo where convert(nvarchar,getdate(),23)='{0}' ...
- Django中的ORM相关操作:F查询,Q查询,事物,ORM执行原生SQL
一 F查询与Q查询: 1 . F查询: 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较.如果我们要对两个字段的值做比较,那该怎么做呢? Django 提供 F() 来做这样的 ...
- django系列5.4--ORM中执行原生SQL语句, Python脚本中调用django环境
ORM执行原生sql语句 在模型查询API不够用的情况下,我们还可以使用原始的SQL语句进行查询. Django 提供两种方法使用原始SQL进行查询:一种是使用raw()方法,进行原始SQL查询并返回 ...
- Django中执行原生SQL语句【新编辑】
参考我的个人博客 这部分迁移到了个人博客中:Django中执行原生SQL语句 这里需要补充一下,还有一个extra方法: ret = models.Student.objects.all().extr ...
- thinkPHP框架中执行原生SQL语句的方法
这篇文章主要介绍了thinkPHP框架中执行原生SQL语句的方法,结合实例形式分析了thinkPHP中执行原生SQL语句的相关操作技巧,并简单分析了query与execute方法的使用区别,需要的朋友 ...
- Hibernate执行原生SQL返回List<Map>类型结果集
我是学java出身的,web是我主要一块: 在做项目的时候最让人别扭的就是hibernate查询大都是查询出List<T>(T指代对应实体类)类型 如果这时候我用的联合查询,那么返回都就是 ...
- Django之ORM其他骚操作 执行原生SQl
Django ORM执行原生SQL # extra # 在QuerySet的基础上继续执行子语句 # extra(self, select=None, where=None, params=Non ...
- 关于No Dialect mapping for JDBC type :-9 hibernate执行原生sql语句问题
转自博客http://blog.csdn.net/xd195666916/article/details/5419316,同时感谢博主 今天做了个用hibernate直接执行原生sql的查询,报错No ...
- sqlalchemy 执行原生sql语句
from contextlib import contextmanager from sqlalchemy import create_engine, ForeignKey from sqlalche ...
随机推荐
- PHP标准注释
"php是一门及其容易入门的语言,刚入门的新手不到几分钟的时间可能就会用echo打印出一个hello world !但是他是真正的程序员吗?怎么来定义程序员呢?如果想真正成为一个程序员,那么 ...
- MJPhotoBrowser BUG修复
崩溃在loading.progress = (float)receivedSize/expectedSize; 分析:MJPhotoView 执行了hide移除了MJPhotoLoadingView, ...
- ESXi 强制4G内存解决(VMware ESXi 6.0.0.update02 )
手上有个性能不太好的机器,想着装一个系统有点浪费,但是4G内存实际识别只有3.7G,到达不了EXSi的最低4G限制,无法安装.最终找到一个解决方法,经过验证适用于ESXi 6.0. 源自于:ESXi ...
- windows下搭建scrapywindows 7 (64) + python 3.5 (64)
说明 之前在 window 10 (64) + python 3.5 (64) 环境下就已经成功安装了 scrapy,当然也费了不少周折. 由于近日将系统换回 windows 7 (64),再安装 s ...
- tkinter 在 x window 下的字体设置格式
X Font Descriptors # X Font Descriptors are strings having the following format (the asterisks repre ...
- poj1014(还需要改动)
#include <stdio.h> int n[6]; int main() { freopen("in.txt","r",stdin); int ...
- IOS 本地推送 IOS10.0以上 static的作用 const的作用
//需要在AppDelegate里面启动APP的函数 加上 UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNot ...
- 【转】js判断手机访问网页
原理:原理有两个,第一:通过游览器(browser)判断是否是手机:第二:通过访问终端判断是否是手机(userAgent):但是通常考虑到兼容性,需要这两种原理同时使用:具体的实现如下: JS实现: ...
- myeclipse项目编码方式彻底设置
我们团队6月10号开始做龙泉瓯江青瓷有限公司的ERP系统,采用java语言开发,在开发时我们采用的是java的流行框架struts2,前端脚本都用jquery框架,开发IDE用的是myeclipse, ...
- PS:蓝天白云的制作
方法一: 1.新建(ctrl+N),根据自己的需求设置画面大小: 2.设置前景色为蓝天颜色,alt+delete,填充为天空蓝颜色: 3.滤镜-渲染-云彩,得出蓝天白云效果: 4.根据需求再调整亮度. ...