EFCore3.1+编写自定义的EF.Functions扩展方法
本文主要是讲解EF Core3.0+ 如何实现自定义的数据库扩展函数
虽然EF.Functions 提供了很多数据库函数,但是并不全面.比如加密解密..
这样的话 我们就需要自己扩展这些数据库函数 从而达到调用的目的.
本文以达梦数据库为例(其他数据库都一样)..
上篇文章推荐:
EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录
1.创建扩展方法
首先我们需要创建自定义的扩展方法如下:
public static class DbFunctionsExtensions
{
/// <summary>
/// 调用数据库的加密方法
/// </summary>
/// <param name="_"></param>
/// <param name="context"></param>
/// <param name="typeid"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string DmAlgorithmsEncrypt(this DbFunctions _, string context, int typeid, string key)
{
throw new InvalidOperationException(
"该方法仅用于实体框架核心,没有内存实现。");
} /// <summary>
/// 调用数据库的解密方法
/// </summary>
/// <param name="_"></param>
/// <param name="context"></param>
/// <param name="typeid"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string DmAlgorithmsDecrypt(this DbFunctions _, string context, int typeid, string key)
{
throw new InvalidOperationException(
"该方法仅用于实体框架核心,没有内存实现。");
}
很简单,我们只需要定义2个静态扩展方法,并且抛出一个InvalidOperationException异常即可.
2.创建调用方法转换器(IMethodCallTranslator)
这里记住IMethodCallTranslator这个接口,我们需要实现它,如下:
public class DmDbFunctionsTranslateImpl : IMethodCallTranslator
{
private readonly ISqlExpressionFactory _expressionFactory; private static readonly MethodInfo _dmAlgorithmsEncryptMethod
= typeof(DbFunctionsExtensions).GetMethod(
nameof(DbFunctionsExtensions.DmAlgorithmsEncrypt),
new[] { typeof(DbFunctions), typeof(string), typeof(int), typeof(string) }); private static readonly MethodInfo _dmAlgorithmsDecryptMethod
= typeof(DbFunctionsExtensions).GetMethod(
nameof(DbFunctionsExtensions.DmAlgorithmsDecrypt),
new[] { typeof(DbFunctions), typeof(string), typeof(int), typeof(string) }); public DmDbFunctionsTranslateImpl(ISqlExpressionFactory expressionFactory)
{
_expressionFactory = expressionFactory;
} public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList<SqlExpression> arguments)
{
//判断方法是否一致
if (method == _dmAlgorithmsEncryptMethod)
{
var args = new List<SqlExpression> { arguments[1], arguments[2], arguments[3] };
return _expressionFactory.Function(instance, "CFALGORITHMSENCRYPT", args, typeof(string));
}
if (method == _dmAlgorithmsDecryptMethod)
{
var args = new List<SqlExpression> { arguments[1], arguments[2], arguments[3] };
return _expressionFactory.Function(instance, "CFALGORITHMSDECRYPT", args, typeof(string));
} return null;
} }
3.创建调用转换器提供程序(RelationalMethodCallTranslatorProvider)
public sealed class DmAlgorithmsMethodCallTranslatorPlugin : RelationalMethodCallTranslatorProvider
{
public DmAlgorithmsMethodCallTranslatorPlugin(RelationalMethodCallTranslatorProviderDependencies dependencies)
: base(dependencies)
{
ISqlExpressionFactory expressionFactory = dependencies.SqlExpressionFactory;
AddTranslators(
new IMethodCallTranslator[]
{
//这里,将刚刚的方法转换器添加到扩展
new DmDbFunctionsTranslateImpl(expressionFactory)
}); } }
这个类主要是将我们刚刚创建的方法转换器添加SQL表达式工厂(SqlExpressionFactory)当中.
4.创建DbContext扩展类(IDbContextOptionsExtension)
代码如下,关键点加了注释,自行参考..
public class DmDbContextOptionsExtension : IDbContextOptionsExtension
{
private DbContextOptionsExtensionInfo _info; public void Validate(IDbContextOptions options)
{
} public DbContextOptionsExtensionInfo Info
{
get
{
return this._info ??= new MyDbContextOptionsExtensionInfo(this);
}
} void IDbContextOptionsExtension.ApplyServices(IServiceCollection services)
{
//这里将转换器注入到服务当中.
services.AddSingleton<IMethodCallTranslatorProvider, DmAlgorithmsMethodCallTranslatorPlugin>();
} private sealed class MyDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo
{
public MyDbContextOptionsExtensionInfo(IDbContextOptionsExtension instance) : base(instance) { } public override bool IsDatabaseProvider => false; public override string LogFragment => ""; public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
{
} public override long GetServiceProviderHashCode()
{
return 0;
}
}
}
5.创建DbContext生成时的扩展方法
public static class DmDbContextOptionsBuilderExtensions
{
public static DbContextOptionsBuilder UseDmAlgorithmsEncryptionFunctions(
this DbContextOptionsBuilder optionsBuilder)
{
//将自定义的配置类添加到配置选项中
var extension = GetOrCreateExtension(optionsBuilder);
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); return optionsBuilder;
} //生成创建扩展类
private static DmDbContextOptionsExtension GetOrCreateExtension(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.Options.FindExtension<DmDbContextOptionsExtension>()
?? new DmDbContextOptionsExtension();
}
6.编写测试代码,查看使用效果
我们先在数据库插入一条加密数据如下:
insert into "tab"."tab"( "XingMing", "ZhengJianHao", "ShouJiHao")
VALUES( '测试数据1', CFALGORITHMSENCRYPT('123456789',514,'ABC'),'77777');
然后我们编写查询代码:
var ddd= Context.Where(a => EF.Functions.DmAlgorithmsDecrypt(a.ZhengJianHao, 514, "ABC") == "123456789").First();
这里,我们将数据解密后在对比
查询效果如下:
我们通过监控SQL语句 可以看到如下SQL语句:
这里,已经将我们的自定义扩展函数转换成了SQL函数 并在数据库执行了.
这里我们就完成了整个SQL函数的扩展. 写这篇主要是为了抛砖引玉..
目前这种扩展方式,在查询的时候 可以正常的生成SQL语句,
但是在ADD 和Update的时候 并不会生成对应的语句,所以想问问各位大佬,有没有更好的实现方式.
EFCore3.1+编写自定义的EF.Functions扩展方法的更多相关文章
- 自定义MVC的Helper扩展方法
记得在开发ASP.NET时候,也经常性使用C#可以写自己义的扩展方法,如:http://www.cnblogs.com/insus/p/3154363.html 或http://www.cnblogs ...
- 自定义MVC的Helper扩展方法 转 Insus.NET
记得在开发ASP.NET时候,也经常性使用C#可以写自己义的扩展方法,如: http://www.cnblogs.com/insus/p/3154363.html 或http://www.cnblog ...
- AbpVnext使用分布式IDistributedCache Redis缓存(自定义扩展方法)
AbpVnext使用分布式IDistributedCache缓存from Redis(带自定义扩展方法) 我的依赖包的主要版本以及Redis依赖如下 1:添加依赖 <PackageReferen ...
- C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询
1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...
- C#学习笔记(八):扩展方法
还记得第一次使用DOTween时,发现缓动方法竟然是可以直接用Transform对象中调用到,当时就被震撼到了(那是还是C#小白一只).好了不多说了,今天来学习一下C#的这个特性——扩展方法. 扩展方 ...
- 【jQuery基础学习】08 编写自定义jQuery插件
目的:虽然jQuery各种各样的功能已经很完善了,但是我们还是要学会自己去编写插件.这样我们可以去封装一些项目中经常用到的专属的代码,以便后期维护和提高开发效率. jQuery插件的类型: 封装对象方 ...
- WinForm TextBox自定义扩展方法数据验证
本文转载:http://www.cnblogs.com/gis-crazy/archive/2013/03/17/2964132.html 查看公司项目代码时,存在这样一个问题:winform界面上有 ...
- JavaScript学习总结(十四)——JavaScript编写类的扩展方法
在JavaScript中可以使用类的prototype属性来扩展类的属性和方法,在实际开发当中,当JavaScript内置的那些类所提供的动态 ...
- 使用自定义验证组件库扩展 Windows 窗体
使用自定义验证组件库扩展 Windows 窗体 1(共 1)对本文的评价是有帮助 - 评价此主题 发布日期 : 8/24/20 ...
随机推荐
- 多种转弯角度的PBN旁切转弯图例分析
无论世界怎样变化,我们依然是有点阳光就灿烂.面对世界的未知,最好的状态是勇敢的去面对,努力的去生活. 今天我们继续来聊一下PBN旁切转弯. PBN转弯保护区的结构通常都与它们的转弯角度大小有关,转弯角 ...
- oracle impdp ORA-02304 invalid object identifier literal
reference: https://webgeest.blogspot.com/2015/07/ora-39083-ora-02304-on-impdp-datapump.html 解决方法 ...
- Linux解压缩相关命令
Linux解压缩相关命令 运行级别: 0:关机 1:单用户 2:多用户无网络连接 3:多用户有网络连接 4:系统保留 5:图形界面 6:系统重启 通过init[0123456]来切换不同的运行级别 g ...
- 顶级c程序员之路 基础篇 - 第一章 关键字的深度理解 number-1
c语言有32个关键字,每个关键字你都理解吗? 今天出场的是: auto , register, static, extern 为什么他们会一起呢,说到这里不得不谈到c语言对变量的描述. c给每 ...
- 基于url-to-pdf-api构建docker镜像,制作一个网页另存服务
基于url-to-pdf-api构建docker镜像,制作一个网页另存服务 业务背景: 需要根据一个url路径打印这个网页的内容 解决方案: 1.使用wkhtml2pdf 2.使用puppeteer ...
- java拼接JSON串
String str = "{\"route\":\"onGift\",\"time\":\"\",\&quo ...
- Go语言学习:01-基本语法
目录 基本语法 源文件构成 数据类型 基本类型变量 数组 切片 创建切片 调整容量 字符串与切片 常量 String Map 控制 条件语句 if switch 循环语句 函数 函数定义 函数变量 闭 ...
- E: Some index files failed to download. They have been**
转: E: Some index files failed to download. They have been** 问题描述: 当使用Dockerfile从包含cuda的镜像建立新的image的时 ...
- SQL学习笔记——创建数据库显示:文件激活错误,物理文件名不存在>>解决方案
今天在创建数据库时,跟着老师一步一步的操作创建成功,但出于在厌恶冗长的数据库存储路径,于是,擅自更改了数据filename,让他保存在电脑桌面新建的文件夹,可是一执行就报错了. 老师源码: 1 cre ...
- Get和Post请求方式
Get和Post是两种不同的类型的请求. 它们主要有3点不同. 1.get请求通过浏览器地址栏传递表单数据.post请求通过form data 传递数据,不会通过地址栏. 2.get请求安全性较低,p ...