前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >EFCore3.1+编写自定义的EF.Functions扩展方法

EFCore3.1+编写自定义的EF.Functions扩展方法

作者头像
GuZhenYin
发布2021-04-16 10:48:54
6330
发布2021-04-16 10:48:54
举报
文章被收录于专栏:GuZhenYinGuZhenYin

前言

本文主要是讲解EF Core3.0+ 如何实现自定义的数据库扩展函数

虽然EF.Functions 提供了很多数据库函数,但是并不全面.比如加密解密..

这样的话 我们就需要自己扩展这些数据库函数 从而达到调用的目的.

本文以达梦数据库为例(其他数据库都一样)..

上篇文章推荐:

EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录

正文

1.创建扩展方法

首先我们需要创建自定义的扩展方法如下:

代码语言:javascript
复制
 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这个接口,我们需要实现它,如下:

代码语言:javascript
复制
 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)

代码语言:javascript
复制
 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)

代码如下,关键点加了注释,自行参考..

代码语言:javascript
复制
 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生成时的扩展方法

代码语言:javascript
复制
    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.编写测试代码,查看使用效果

我们先在数据库插入一条加密数据如下:

代码语言:javascript
复制
insert into "tab"."tab"( "XingMing", "ZhengJianHao", "ShouJiHao") 
VALUES( '测试数据1', CFALGORITHMSENCRYPT('123456789',514,'ABC'),'77777');

然后我们编写查询代码:

代码语言:javascript
复制
var ddd= Context.Where(a => EF.Functions.DmAlgorithmsDecrypt(a.ZhengJianHao, 514, "ABC") == "123456789").First();

这里,我们将数据解密后在对比

查询效果如下:

我们通过监控SQL语句 可以看到如下SQL语句:

这里,已经将我们的自定义扩展函数转换成了SQL函数 并在数据库执行了.

写在最后

这里我们就完成了整个SQL函数的扩展. 写这篇主要是为了抛砖引玉..

目前这种扩展方式,在查询的时候 可以正常的生成SQL语句,

但是在ADD 和Update的时候 并不会生成对应的语句,所以想问问各位大佬,有没有更好的实现方式.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-04-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.创建扩展方法
  • 2.创建调用方法转换器(IMethodCallTranslator)
  • 3.创建调用转换器提供程序(RelationalMethodCallTranslatorProvider)
  • 4.创建DbContext扩展类(IDbContextOptionsExtension)
  • 5.创建DbContext生成时的扩展方法
  • 6.编写测试代码,查看使用效果
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档