zoukankan      html  css  js  c++  java
  • 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的时候 并不会生成对应的语句,所以想问问各位大佬,有没有更好的实现方式.

    作者:顾振印 出处:http://www.cnblogs.com/GuZhenYin/ 如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面
  • 相关阅读:
    python爬虫之urllib库(三)
    python爬虫之urllib库(二)
    认识CSS中css引入方式、选择器、文本样式设置以及显示模式
    认识CSS中盒子模型
    python爬虫之urllib库(一)
    认识CSS中css背景样式设置
    python爬虫之认识爬虫和爬虫原理
    认识CSS中css的三大特性:层叠性、继承性以及优先级
    认识HTML中表格、列表标签以及表单控件
    python-基础学习篇(八)
  • 原文地址:https://www.cnblogs.com/GuZhenYin/p/14657024.html
Copyright © 2011-2022 走看看