首页 > 数据库 >老派Sql之必要,逆天,我在ef core中使用ado.net!

老派Sql之必要,逆天,我在ef core中使用ado.net!

时间:2023-08-05 13:11:25浏览次数:40  
标签:core sqlFormatter full Console ef dbContext WriteLine ado id

DimTechStudio.Com

Wlkr.Core.EFCore

逆天,我在ef core中使用ado.net!

老派Sql之必要

  • 当你开发生涯中基本只用一两种数据库
  • 当你觉得用EF的类写报表时很别扭
  • 当你觉自己的Sql( Server)语句写得出神入化
  • 当你觉自己的Sql( Server)语句比EF生成的更优化
  • 当你刚从.net framework转.net core,还不知道sqlsugar和dapper

如上面所说,本项目在几年前,笔者刚转到.net core 3.1的开发中,编写了此项目。
当时觉得ef core这的很强大,编写业务代码时,效率提升极高,层次结构、逻辑代码都很清晰统一。
但是到了开发报表时,多表关联,奇葩条件组合就显示很别扭,各种奇怪的select,join,where等操作用于类中,令人抓狂,在sql语句中可能几行能写完的东西,夸张点可能得写上几十行,即便有linq和lambda的辅助,也没有直接写sql好用。
于是便诞生了此项目。

食用方式

EFCoreQueryHelper此类基本功能分为SqlQuery,SqlNonQuery,SqlScalar,Reader及DataSet。
每个类型有3中接口

  • 第一种直接使用string,不能防止SQL注入。
  • 第二种使用FormattableString,能防止SQL注入
  • 第三种我封装的SqlFormatter,实现像StringBuilder一样拼接FormattableString

Console项目“EFCoreSample”里面有一些使用示例

环境准备

  • 你需要Sql server,.net6 SDK
  • 在Console中默认没有从appsettings.json读取config的功能,此处我们自己先构造一个config。
//读取Config
var configuration = new ConfigurationBuilder()
        .SetBasePath(AppContext.BaseDirectory) // 设置基础路径为应用程序根目录
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) // 加载 appsettings.json 文件
        .AddEnvironmentVariables() // 可以添加环境变量的配置
        .AddCommandLine(args) // 可以添加命令行参数的配置
        .Build();
  • 然后构造一个DbContext
    平时都是web api项目里注入,Console差点不会写……
//配置DbContext
EFCoreQueryHelper.Configuration = configuration;
string constr = "Default";
DbContextOptionsBuilder<EFCoreSampleDbContext> optionsBuilder = new DbContextOptionsBuilder<EFCoreSampleDbContext>
    ();
optionsBuilder.UseSqlServer(configuration.GetConnectionString(constr));
using EFCoreSampleDbContext dbContext = new EFCoreSampleDbContext(optionsBuilder.Options);
  • 再执行迁移及种子数据
//自动迁移
if (dbContext.Database.GetPendingMigrations().Any())
    dbContext.Database.Migrate();
//种子数据
void AddSeedData()
{
    if (dbContext.TestModels.Any(t => t.Id == 1))
        return;
    for (var i = 1; i < 100; i++)
    {
        TestModel testModel = new TestModel()
        {
            //Id = i,
            S = "S" + i.ToString(),
            L = i,
            B = i % 2 == 0 ? true : false,
            D = i,
            F = i,
            G = Guid.NewGuid(),
            CreateDate = DateTime.Now
        };
        dbContext.Add(testModel);
    }
    dbContext.SaveChanges();
}
AddSeedData();

测试环境已准备好,下面进入正题,该如何使用。

如何防SQL注入

防SQL注入的核心,是使用FormattableString,从中提取格式化的字符串,及其参数变量,从而转换为SqlParameter[],在ado.net里执行。

使用FormattableString

  • 方法名带Interpolated后缀的,都是防SQL注入
//查询示例
Console.WriteLine("防注入:");
List<TestModel> full = dbContext.SqlQueryDynamicInterpolated<TestModel>($"select * from TestModel where id = {id}");
Console.WriteLine("full:");
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(full));
Console.WriteLine();
//部分字段
List<TestModel> part = dbContext.SqlQueryDynamicInterpolated<TestModel>($"select S from TestModel where id = {id}");
Console.WriteLine("part:");
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(part));
Console.WriteLine();
//动态对象,本质是ExpandoObject
IEnumerable<dynamic> dyn = dbContext.SqlQueryDynamicInterpolated($"select S from TestModel where id = {id}");
Console.WriteLine("dyn:");
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(dyn));
Console.WriteLine();
  • 要注意区分FormattableString($"")和string("")的使用
    下面方法不带Interpolated,虽然也是用了FormattableString,但它最终会是string,没法防SQL注入。
    在传统的ado.net中,下面的{id}应该改为@p0,参数化才能防SQL注入。
//以下是纯粹的拼接字符串,不能防Sql注入,不推荐
full = dbContext.SqlQueryDynamic<TestModel>($"select * from TestModel where id = {id}", new SqlParameter[] { });
Console.WriteLine("不防注入:");
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(full));
Console.WriteLine();

使用SqlFormatter

$"" 的缺点是不能拼接如$"" + $"",它会变为string,导致不能防SQL注入。
此时需要想StringBuilder一样,封装一个可以Append字符串的类。

SqlFormatter sqlFormatter = new SqlFormatter("select * from TestModel where 1=1 ");
//参数化条件
if (true)
    sqlFormatter.AppendLine_FmtStr($"and id = {id}");
//不需要参数化的条件
if (true)
    sqlFormatter.AppendLine_Str("and S = 'S1'");
//主要看{},这也是参数化
if (true)
    sqlFormatter.AppendLine_FmtStr($"and S = {"S" + id}");
sqlFormatter.AppendLine_FmtStr($"or L = {2}");
sqlFormatter.AppendLine_FmtStr($"or F = {3}");
sqlFormatter.AppendLine_FmtStr($"or D = {4}");
sqlFormatter.AppendLine_FmtStr($"or (B = {false} and id in (5,7,9) )");
Console.WriteLine(sqlFormatter.FormatedSql);
full = dbContext.SqlQueryDynamic<TestModel>(sqlFormatter.FormatedSql, sqlFormatter.Parameters);
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(full));
Console.WriteLine();

可以看到sqlFormatter.FormatedSql中已经将{p}转化为@p。

使用SqlPaging

报表开发中用的最多的当然是分页了,结合SqlFormatterSqlPagingPagingUtil,实现分页查询。

//分页例子
Console.WriteLine("SqlPaging分页:");
//先构建条件,约等于id为奇数的数据
sqlFormatter = new SqlFormatter();
sqlFormatter.AppendLine_FmtStr($"and t.B = {false}");

//除了等号逗号,写法基本与sql语句一致
SqlPaging sqlPaging = new SqlPaging()
{
    db = dbContext,
    Select = "*",
    From = "TestModel t",
    WhereBuilder = sqlFormatter,
    OrderBy = " t.id desc"
};

//每页10条
full = sqlPaging.Execute<TestModel>();
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(sqlPaging.PagingUtil));
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(full));
Console.WriteLine();

//每页5条,第三页
sqlPaging.PagingUtil.PageSize = 5;
sqlPaging.PagingUtil.PageIdx = 3;
full = sqlPaging.Execute<TestModel>();
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(sqlPaging.PagingUtil));
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(full));
Console.WriteLine();

EF、SqlSugar、Dapper对比

除了开始不知道后面两个外,我喜欢EF的Migration功能,它比SqlSugar强。
而且使用EF,显得相当清真,它又是我自己写,自己用的类库,它不需要它复杂的功能,满足我日常使用即可。
反射方面的性能没有对比,暂略。

其他

既然是老派SQL,当然少不了DbFirst。
后续补充DbFirst转CodeFirst开发模式。
To Be Continue...

Author Info

DimWalker
©2023 广州市增城区黯影信息科技部
https://www.dimtechstudio.com/

标签:core,sqlFormatter,full,Console,ef,dbContext,WriteLine,ado,id
From: https://www.cnblogs.com/jine1987/p/17607814.html

相关文章

  • .NetCore + Selenium IIS 部署踩坑记
    一、问题   使用Selenium+chromedriver开发自动操作页面demo,本地调试使用IISExpress正常,部署到IIS访问接口代码正常执行,但是,但是页面并没有启动二、排查  网上找相似情况大概以下几种 1,chromedriver和chrome的版本不一致 2,IIS用户权限 3,代码写法问题 本......
  • 二维数组花式遍历(旋转,螺旋) [labuladong-刷题打卡 day5]
    矩阵旋转48.旋转图像难点主要在于:用翻转和镜像处理逆反和旋转,和逆转单词一样“难者不会,会者不难”,思路简单镜像的坐标对应关系处理语言特性的利用,不同语言有不同api,实际代码中会有很大不同,但思想一致如果确定矩阵维数,通过线性代数应该可以直接计算答案...classSolution......
  • indesign软件下载_adobe indesign下载 官方版特色
    AdobeInDesign2023官方版是用于印刷和数字媒体的业界领先的版面和页面设计软件。利用顶级字体公司的印刷字体和各种图像,创作精美的平面设计。快速共享PDF中的内容和反馈。通过AdobeExperienceManager轻松管理制作。InDesign具备创建和发布书籍、数字杂志、电子书、海报和......
  • ID软件下载Adobe InDesign2023安装包+教程(全版本) 官方版特色
    InDesignCC2020中文版是一款适合页面设计时使用的专业高效的页面排版设计工具,InDesignCC2020中文版功能强劲,能够帮助用户快速完美地控制设计在印刷样式中的各个像素,InDesignCC2020软件操作非常简便,可让您建立精美且吸引人的成果,将其用于印刷或显示在画面中。软件地址:看置顶贴......
  • Adobe Dreamweaver 2022官方版_最新免费版下载安装 官方版特色
    AdobeDreamweaver2021亮点1.快速.灵活的编码借助简化的智能编码引擎,轻松创建.编码和管理动态网站。访问代码提示,用于快速理解和编辑HTML.CSS和其他Web标准。利用视觉辅助功能减少错误,提高网站开发速度。2.通过较少的步骤轻松设置网站使用起始模板更快地启动和运行您的网站,您可以通......
  • 拷贝完hadoop集群后如何恢复网络
    流年似飞雪:结论:拷贝集群后不用重新配置网络知识:ip由四位组成,前三位是网络标识最后一个是端口ip你原先用的主机网络标识符是192.168.10,拷过来的集群的网络标识符为192.168.111,就把第三位的10改成111,网络标识得和拷过来的主机一致,都是192.168.111步骤:查看hadoop......
  • 【高并发】SimpleDateFormat类到底为啥不是线程安全的?(附六种解决方案,建议收藏)
    大家好,我是冰河~~首先问下大家:你使用的SimpleDateFormat类还安全吗?为什么说SimpleDateFormat类不是线程安全的?带着问题从本文中寻求答案。提起SimpleDateFormat类,想必做过Java开发的童鞋都不会感到陌生。没错,它就是Java中提供的日期时间的转化类。这里,为什么说SimpleDateFormat类有......
  • cdh4 hadoop,hive,impala,hbase本地库搭建及安装
    --hadoop文件位置:log目录:1 /var/log/hadoop-hdfs2 /var/log/hadoop-mapreduce3 /var/log/hbase4 /var/log/hive5 /var/log/hive6 /var/log/impala安装目录:1 /usr/lib启动命令目录:1 /etc/init.d/配置文件目录:1 /etc/hadoop/conf2 /etc/hbase/conf3 /etc/hive/conf......
  • Codeforces Round 882 (Div. 2)
    link题号:CF1847A~FA题意:给定一个数组\(\{x_1,x_2,\cdots,x_n\}\)和一个整数\(k\),记\(f(l,r)=\sum_{i=0}^{i<r-l}|x_{l+i}-x_{l+i+1}|\),求将数组划分为\(k\)个部分的划分方案,使得对每个部分的\(f(l,r)\)之和最小.题解:简单题,首先我们注意到,如果将\(l,l+1\)隔开,那......
  • [maven]java.lang.NoSuchMethodError: org.apache.maven.model.validation.DefaultMod
    Maven异常环境idea版本:2020.1.3maven版本:3.8.5问题描述在idea中加入maven配置时,idea一直报出java.lang.NoSuchMethodError:org.apache.maven.model.validation.DefaultModelValidator异常异常信息1)Errorinjectingconstructor,java.lang.NoSuchMethodError:org.......