前言

本文主要是讲解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. 编写自定义的字符串一致性匹配方法,只要两个字符串包含同样的字符, 不管字符的顺序如何,都认为两个字符串一致,如:”aabbcc”和”abcabc”被认为是一致的...

    <pre name="code" class="java"> package com.huiwen; import java.util.Scanne ...

  2. 编写自定义的字符串一致性匹配方法,只要两个字符串包含同样的字符, 不管字符的顺序如何,都认为两个字符串一致,如:”aabbcc”和”abcabc”被认为是一致的

    <pre name="code" class="java"> package com.huiwen; import java.util.Scanne ...

  3. spock框架_Spock VW:编写自定义的Spock框架扩展

    spock框架 Spock框架具有多个内置扩展 ,这些扩展支持许多核心功能,例如@Ignore和@Timeout批注. 但更重要的是,鼓励开发人员编写自己的扩展. 例如, SpringExtensio ...

  4. Spock VW:编写自定义的Spock框架扩展

    Spock框架具有多个内置扩展 ,这些扩展支持许多核心功能,例如@Ignore和@Timeout批注. 但更重要的是,鼓励开发人员编写自己的扩展. 例如, SpringExtension很好地将Spo ...

  5. C#中的扩展方法学习总结

      版权声明:本文由秦元培创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,转载请注明作者及出处,本文作者为秦元培,本文标题为C#中的扩展方法学习总结,本文 ...

  6. CodeGen编写自定义表达式标记

    CodeGen编写自定义表达式标记 CodeGen支持开发人员通过编写plug-in modules插件模块来定义自定义表达式标记的能力,以提供与这些标记相关联的逻辑.这种plug-in module ...

  7. 编写 Debugging Tools for Windows 扩展,第 1 部分 (windbg 插件 扩展)

    调试器 API 编写 Debugging Tools for Windows 扩展 Andrew Richards 下载代码示例 http://download.csdn.net/detail/wha ...

  8. Kubernetes 编写自定义 controller

    原文链接:Kubernetes编写自定义controller 来自kubernetes官方github的一张图: 如图所示,图中的组件分为client-go和custom controller两部分: ...

  9. 【MSDN文摘】使用自定义验证组件库扩展 Windows 窗体: Form Scope

    使用自定义验证组件库扩展 Windows 窗体,第 2 部分(Windows 窗体探索) 发布日期: 5/28/2004 | 更新日期: 5/28/2004 Michael Weinhardt www ...

最新文章

  1. react native release语法问题解决
  2. Android--解析XML之SAX
  3. java中的 FileWriter类 和 FileReader类的一些基本用法
  4. 从Oracle Database 角度来看浪潮天梭K1主机的操作系统选择
  5. java arraylist 字符串数组_java中String,数组,ArrayList三者之间的转换
  6. 使用Jsoup实现网络爬虫
  7. 《数据结构》考研天勤和王道 第三章 栈、队列、数组和广义表
  8. next项目部署到服务器pm2进程守护
  9. 关于onclick=open([Object obj],[Object obj])的问题
  10. mysql查询数据1168_mysqldump 1168 error
  11. github官网进不去解决方案
  12. kali配置静态IP地址
  13. 华为路由器交换机eNSP配置命令
  14. MySQL 8 的学习——4从表中检索信息
  15. 5个强大的Excel仪表板
  16. 贝格尔编排法-java
  17. 毕业论文选题基于Web网站或Android APP的设计与实现
  18. 在线图片压缩网站TinyPNG
  19. 如何通过 HTML+CSS+JS 制作焦点轮播图
  20. Java项目:springboot大学生实习管理系统

热门文章

  1. linux网卡固件名,修改CentOS7网卡名称为传统名称eth0格式
  2. python词频统计代码_python统计词频
  3. that is why用法
  4. 第4章 变量、作用域和内存问题
  5. java - 匿名类
  6. 通过api管理grafana
  7. SpringBoot+Mybatis 框架之 @SelectProvider注解方式搭建
  8. 数据库、表、表内容增删改查
  9. jenkins2 groovy语法
  10. IOS原生地图与高德地图