前言

本文主要是讲解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. react UI 框架对比

    传送门  https://blog.csdn.net/qiqingjin/article/details/79219206 点击

  2. Techme INC:红光和近红外光疗法有效加速肌肉恢复,美国橄榄球队已采用

    Techme INC创始人兼董事长MADELEINE VAUGHAN表示:在运动结束后,肌肉纤维因为细微损伤造成酸痛情形,即是延迟性肌肉酸痛-DOMS.这类酸痛发生时,需要适度的恢复,避免造成肌肉拉伤 ...

  3. 加州金融专访NGK,就NGK DeFi+展开讨论

    近日,加利福尼亚金融日报联合数家知名媒体就DeFi+行业专访了NGK团队代表特德惠斯基. 首先,加利福尼亚金融日报专栏记者迈尔斯表示,目前区块链领域,去中心化金融(DeFi+)的概念是目前市场上面最火 ...

  4. React 函数式组件的 Ref 和子组件访问(useImperativeHandle)

    引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...

  5. (数据科学学习手札108)Python+Dash快速web应用开发——静态部件篇(上)

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...

  6. c# 打印面单

    private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { ...

  7. 使用 Tye 辅助开发 k8s 应用竟如此简单(五)

    续上篇,这篇我们来进一步探索 Tye 更多的使用方法.本篇我们来了解一下如何在 Tye 中实现对分布式链路追踪. Newbe.Claptrap 是一个用于轻松应对并发问题的分布式开发框架.如果您是首次 ...

  8. Spring Cloud基础

    1.网站架构演变过程 传统架构(单点应用SSM或SSH)→分布式架构(项目拆分)→SOA架构(面向服务架构)→微服务架构 2.微服务概述 2.1SOA架构 面向服务的架构(SOA)是一个组件模型,它将 ...

  9. Android 开发学习进程0.28 腾讯TBS接入和相关问题

    TBS 的接入和使用 TBS 的接入 腾讯TBS是X5内核的升级版,可以当作webview 来打开 网页,可以以用来打开docx doc pdf 等文件,这里主要使用的是文件功能. 依赖接入 api ...

  10. 再来认识一下 Java 序列化

    前言 在面试中,Java 序列化被问到的几率还是挺高的.所以搜集了 Java 序列化常见的问题,由浅入深的帮助大家进一步学习和理解. 序列化基础知识 什么是序列化? Java 序列化是 JDK 1.1 ...