前言

本文主要是讲解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扩展方法的更多相关文章

  1. 自定义MVC的Helper扩展方法

    记得在开发ASP.NET时候,也经常性使用C#可以写自己义的扩展方法,如:http://www.cnblogs.com/insus/p/3154363.html 或http://www.cnblogs ...

  2. 自定义MVC的Helper扩展方法 转 Insus.NET

    记得在开发ASP.NET时候,也经常性使用C#可以写自己义的扩展方法,如: http://www.cnblogs.com/insus/p/3154363.html 或http://www.cnblog ...

  3. AbpVnext使用分布式IDistributedCache Redis缓存(自定义扩展方法)

    AbpVnext使用分布式IDistributedCache缓存from Redis(带自定义扩展方法) 我的依赖包的主要版本以及Redis依赖如下 1:添加依赖 <PackageReferen ...

  4. C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询

    1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...

  5. C#学习笔记(八):扩展方法

    还记得第一次使用DOTween时,发现缓动方法竟然是可以直接用Transform对象中调用到,当时就被震撼到了(那是还是C#小白一只).好了不多说了,今天来学习一下C#的这个特性——扩展方法. 扩展方 ...

  6. 【jQuery基础学习】08 编写自定义jQuery插件

    目的:虽然jQuery各种各样的功能已经很完善了,但是我们还是要学会自己去编写插件.这样我们可以去封装一些项目中经常用到的专属的代码,以便后期维护和提高开发效率. jQuery插件的类型: 封装对象方 ...

  7. WinForm TextBox自定义扩展方法数据验证

    本文转载:http://www.cnblogs.com/gis-crazy/archive/2013/03/17/2964132.html 查看公司项目代码时,存在这样一个问题:winform界面上有 ...

  8. JavaScript学习总结(十四)——JavaScript编写类的扩展方法

    在​J​a​v​a​S​c​r​i​p​t​中​可以使​用​类的p​r​o​t​o​t​y​p​e属性来​扩​展​类的属​性​和​方​法,在实际开发当中,当JavaScript内置的那些类所提供的动态 ...

  9. 使用自定义验证组件库扩展 Windows 窗体

    使用自定义验证组件库扩展 Windows 窗体             1(共 1)对本文的评价是有帮助 - 评价此主题                          发布日期 : 8/24/20 ...

随机推荐

  1. NGK底层技术如何助力SPC子币VAST高价与安全并行?

    NGK近来使用了新的侧链技术推出了新的SPC侧链代币,以及SPC的子币VAST---维萨币. NGK使用去中心化和开源区块链数据分布式协议,不断打造高倍币,力求成为生态建设参与者们所信赖的高倍币孵化器 ...

  2. 大胆预计SPC算力空投收益,月收益22.8%

    此前,NGK官方公告表示,NGK算力持有者获得SPC的数量是根据200万枚SPC除以全网算力总量决定的. 举个例子,假设全网算力总量为500万,那么每个算力持有者如果持有一个算力,则可获得200万÷5 ...

  3. 星盟全球投资副总裁DENIEL SOIBIM:如何激发创造力

    丹尼尔·索比姆毕业于加州理工大学,2005年通过创建投资俱乐部对潜力公司进行天使投资,获得了美国Blue Run高层的重视,任营收专家评估师,为Blue Run项目提案做风险评估,09年与泰勒·亚当斯 ...

  4. 快速读懂 HTTP/3 协议

    在 深入浅出:HTTP/2 一文中详细介绍了 HTTP/2 新的特性,比如头部压缩.二进制分帧.虚拟的"流"与多路复用,性能方面比 HTTP/1 有了很大的提升.与所有性能优化过程 ...

  5. 从HashMap面试聊聊互联网内卷

    微信公众号:大黄奔跑 关注我,可了解更多有趣的面试相关问题. 写在之前 毫无疑问,回想2020年有什么词出现在眼前最多的,无疑是"996"和"内卷",从马老师的 ...

  6. Linux系列 -- XShell破解版安装教程

    目录 一.xshell6商业版安装教程 1. 为什么要用xshell 2. 打开Keygen软件获取注册码 3.安装Xmanager_PowerSuite软件 4.打开康康. 二.XShell远程连接 ...

  7. 使用gitlab构建基于docker的持续集成(二)

    使用gitlab构建基于docker的持续集成(二) gitlab docker aspnetcore Centos配置gitlab镜像并且启动 Centos配置防火墙 windows上访问gitla ...

  8. std和stl的关系

    [前言]在写程序时,虽然一直这么用,有点疑惑为甚么引入了头文件.h还要在加上using namespace std?例如: 1 #include<iostream> 2 using nam ...

  9. Hexo的详细搭建过程——小白的血泪经历QAQ

    Hexo的详细搭建过程 环境要求: node.js git 这里提供Centos8.2下的安装过程: dnf module list nodejs dnf module install nodejs: ...

  10. 如何使用python爬取网页动态数据

    我们在使用python爬取网页数据的时候,会遇到页面的数据是通过js脚本动态加载的情况,这时候我们就得模拟接口请求信息,根据接口返回结果来获取我们想要的数据. 以某电影网站为例:我们要获取到电影名称以 ...