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 ...
随机推荐
- react UI 框架对比
传送门 https://blog.csdn.net/qiqingjin/article/details/79219206 点击
- Techme INC:红光和近红外光疗法有效加速肌肉恢复,美国橄榄球队已采用
Techme INC创始人兼董事长MADELEINE VAUGHAN表示:在运动结束后,肌肉纤维因为细微损伤造成酸痛情形,即是延迟性肌肉酸痛-DOMS.这类酸痛发生时,需要适度的恢复,避免造成肌肉拉伤 ...
- 加州金融专访NGK,就NGK DeFi+展开讨论
近日,加利福尼亚金融日报联合数家知名媒体就DeFi+行业专访了NGK团队代表特德惠斯基. 首先,加利福尼亚金融日报专栏记者迈尔斯表示,目前区块链领域,去中心化金融(DeFi+)的概念是目前市场上面最火 ...
- React 函数式组件的 Ref 和子组件访问(useImperativeHandle)
引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...
- (数据科学学习手札108)Python+Dash快速web应用开发——静态部件篇(上)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- c# 打印面单
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { ...
- 使用 Tye 辅助开发 k8s 应用竟如此简单(五)
续上篇,这篇我们来进一步探索 Tye 更多的使用方法.本篇我们来了解一下如何在 Tye 中实现对分布式链路追踪. Newbe.Claptrap 是一个用于轻松应对并发问题的分布式开发框架.如果您是首次 ...
- Spring Cloud基础
1.网站架构演变过程 传统架构(单点应用SSM或SSH)→分布式架构(项目拆分)→SOA架构(面向服务架构)→微服务架构 2.微服务概述 2.1SOA架构 面向服务的架构(SOA)是一个组件模型,它将 ...
- Android 开发学习进程0.28 腾讯TBS接入和相关问题
TBS 的接入和使用 TBS 的接入 腾讯TBS是X5内核的升级版,可以当作webview 来打开 网页,可以以用来打开docx doc pdf 等文件,这里主要使用的是文件功能. 依赖接入 api ...
- 再来认识一下 Java 序列化
前言 在面试中,Java 序列化被问到的几率还是挺高的.所以搜集了 Java 序列化常见的问题,由浅入深的帮助大家进一步学习和理解. 序列化基础知识 什么是序列化? Java 序列化是 JDK 1.1 ...