EntityFramework Core 2.0自定义标量函数两种方式

前言

上一节我们讲完原始查询如何防止SQL注入问题同时并提供了几种方式。本节我们继续来讲讲EF Core 2.0中的新特性自定义标量函数。

自定义标量函数两种方式

在EF Core 2.0中我们可以将方法映射到数据库中的标量函数,我们可在LINQ中调用此方法并会被正确翻译成SQL语句,这为编写数据访问层的开发人员提供了一个很棒的功能来创建一个方法并在其上应用DbFunction特性即可。该属性会将静态CLR方法映射到数据库函数,以便可以在LINQ查询中使用此方法。默认情况下,数据库函数中的CLR静态方法名称必须相同,除非我们在DbFunctionAttribute中指定了不同的名称。自定义标量函数必须满足如下两个条件。

 (1)函数必须是静态方法且在上下文中声明。

 (2)只能作为参数标量值返回。

 自定义标量函数方式一

 我们可直接在上下文中定义一个静态方法,如下:

        [DbFunction]       
       
public static string ScalarFunction(string name){        
             
throw new NotImplementedException();}

 自定义标量函数方式二

        public static string ScalarFunction(string name){        
             
throw new NotImplementedException();}

然后在OnModelCreating方法利用ModelBuilder中的HasDbFunction来调用上述方法,如下:

 modelBuilder.HasDbFunction(() => ScalarFunction(null));

请注意以上自定义标量函数的两种方式必须定义架构名称即Schema,否则在调用上述方法查询时将抛出【System.Data.SqlClient.SqlException:“'您自定义的函数名称' 不是可以识别的 内置函数名称。”】,也就是说我们无论是利用DbFunction特性还是HasDbFunction方法映射自定义标量函数也好都必须指定Schema,我们默认指定为dbo,如下:

        [DbFunction(FunctionName = "UdfFunction", Schema = "dbo")]       
       
public static string ScalarFunction(string name){        
             
throw new NotImplementedException();}

或者

public static string ScalarFunction(string name)

        {

            throw new NotImplementedException();

        }


        modelBuilder.HasDbFunction(

            () => ScalarFunction(null)).HasName("UdfFunction").HasSchema("dbo");

        或者

        modelBuilder.HasDbFunction(GetType()

            .GetMethod("ScalarFunction"), options =>

            {

                options.HasName("UdfFunction");

                options.HasSchema("dbo");

            });

上述讲解了在EF Core 2.0中如何创建标量函数,讲了这么多,到底怎么用,或者说它的出现可以解决什么问题呢?下面我们首先来看一个例子。比如我们想查询每篇博客的评论数的均值,接下来我们会进行如下查询:

using (var context = new EFCoreDbContext())

            {

                var blogs = context.Blogs

                  .AsNoTracking();


                var result = blogs.Select(b => new BlogDTO()

                {

                    Id = b.Id,

                    Name = b.Name,

                    Count = b.Posts.Count() > 0 ? b.Posts.Average(d => d.CommentCount) : 0

                }).ToList();

            }

此时将出现函数Average无法翻译成SQL,只能在内存中进行查询。在EF Core中如果您有详细查看过生成的SQL语句的话,您就能够明白,对于Min、Max、Average等LINQ函数,EF Core不支持翻译成远程SQL,只能在本地查询。此时我们再来看看进行此次查询总共耗时100ms,如下:

接下来我们再利用自定义标量函数查询试试。首先定义标量函数

 public static double? UdfAverage(int blogId){        
    
throw new Exception(); }
  modelBuilder.HasDbFunction(() => UdfAverage(default(int))).HasSchema("dbo");

然后我们再来创建标量函数

public static class AddUdfHelper

    {

        public static void AddUdfToDatabase(this DbContext context)

        {

            using (var transaction = context.Database.BeginTransaction())

            {

                try

                {

                    context.Database.ExecuteSqlCommand(

                        "IF OBJECT_ID('dbo.UdfAverage', N'FN') IS NOT NULL " +

                        "DROP FUNCTION dbo.UdfAverage");


                    context.Database.ExecuteSqlCommand(

                        "CREATE FUNCTION UdfAverage (@blogId int)" +

                        @"  RETURNS FLOAT

  AS

  BEGIN

  DECLARE @result AS FLOAT

  SELECT @result = AVG(CAST([CommentCount] AS FLOAT)) FROM dbo.Posts AS p

       WHERE p.BlogId = @blogId

  RETURN @result

  END");

                    transaction.Commit();

                }

                catch (Exception ex)

                {

                    throw ex;

                }

            }

        }

    }

上述标量函数理应在迁移时生成,现在我们首先在上下文构造函数中创建即在运行时创建。在数据库中函数中的标量函数中将生成UdfAverage函数,如下:

接下来我们再来调用创建的自定义标量函数,如下:

using (var context = new EFCoreDbContext())

            {

                var blogs = context.Blogs

                  .AsNoTracking();


                var result = blogs.Select(b => new BlogDTO()

                {

                    Id = b.Id,

                    Name = b.Name,

                    Count = EFCoreDbContext.UdfAverage(b.Id)

                }).ToList();

            }


我们看看此此查询总共耗时77ms。相比上述未调用标量函数直接调用Average方法,不会翻译成SQL,所以在数据库中查询一次,然后加载到内存中再查询一次,效果显而易见。

总结 

本节我们详细讲解了EF Core  2.0中的自定义标量函数,若我们需要进行子查询返回标量值时此时创建自定义标量函数将成为首选,其性能比调用内置的APi然后在内存中进行查询而不会翻译成SQL的性能更好。精简的内容,简单的讲解,希望对阅读的您有所帮助,我们明天再会。


原文:http://www.cnblogs.com/CreateMyself/p/8485697.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322003.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET Core远程调试

关于ASP.NET Core远程调试的具体做法可参考微软文档——Remote Debug ASP.NET Core on a Remote IIS Computer in Visual Studio 2017,详细做法不再赘述,这里主要记录下自己的感受。体验Web Deploy这种发布方式可直接将代码打包发到指定服务器的指定站点…

修复.NET的HttpClient

早在2016年我们就报道过 ,.NET的HttpClient存在一些问题。随着.NET Core 2.1中HttpClientFactory的引入,其中部分问题已经得到缓解。HttpClient的根本问题是,每次调用资源好像都应该在使用后立即释放。在现实中,那意味着每个目标服…

欢乐纪中A组赛【2019.8.20】

前言 Rank1???Rank1???Rank1??? 成绩 RankRankRankPersonPersonPersonScoreScoreScoreAAABBBCCC111(J−3)WYC(J-3)WYC(J−3)WYC145145145100100100000454545212121(J−3)ZYC(J-3)ZYC(J−3)ZYC636363383838000252525353535(J−3)XXY(J-3)XXY(J−3)XXY45454500000045454…

Asp.Net Core2.0 基于QuartzNet任务管理系统

Quartz.NET官网地址:https://www.quartz-scheduler.net/Quartz.NET文档地址:https://www.quartz-scheduler.net/documentation/index.htmlQuartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成…

64位的Mac OS X也有Windows.Forms了

Mono长期以来一直为Linux、Mac和Windows提供Windows.Forms的纯C#实现。随着技术潮流的变化,Mono的Windows.Forms平台仍然没有得到很好的发展,还只是各种第三方库和应用程序的依赖,这使得它的重要性超过了那些基于WinForms的应用程序。Mono默认…

.Net 4.X 提前用上 .Net Core 的配置模式以及热重载配置

1. 前言在提倡微服务及 Serverless 越来越普及的当下,传统 .Net 应用的配置模式往往依赖于一个名为 web.config 的 XML 文件,在可扩展性和可读性与时代脱节了。当然,我不会怂恿一下子把所有应用迁移到 .Net Core 上,本文将在尽量不…

C# 枚举特性 FlagAttribute 的应用

写在前面枚举Enum 全称(Enumeration),即一种由一组称为枚举数列表的命名常量组成的独特类型。可以看出枚举的出现是为了使我们可以在程序中方便的使用一些特定值的常量,一般的使用大家都比较熟悉,本文主要介绍枚举的特性 FlagAttribute。Flag…

重温.NET下Assembly的加载过程

最近在工作中牵涉到了.NET下的一个古老的问题:Assembly的加载过程。虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后发现,并没能解决我的问题,有些点写的不是特别详细,让人…

看eShopOnContainers学一个EventBus

最近在看微软eShopOnContainers 项目,看到事件总线觉得不错,和大家分享一下看完此文你将获得什么?eShop中是如何设计事件总线的实现一个InMemory事件总线eShop中是没有InMemory实现的,这算是一个小小小的挑战发布订阅模式发布订阅…

创建基于MailKit和MimeKit的.NET基础邮件服务

邮件服务是一般的系统都会拥有和需要的功能,但是对于.NET项目来说,邮件服务的创建和使用会较为的麻烦。.NET对于邮件功能提供了System.Net.Mail用于创建邮件服务,该基础服务提供邮件的基础操作,并且使用也较为的简单。对于真正将该…

EF Core下利用Mysql进行数据存储在并发访问下的数据同步问题

小故事在开始讲这篇文章之前,我们来说一个小故事,纯素虚构(真实的存钱逻辑并非如此)小刘发工资后,赶忙拿着现金去银行,准备把钱存起来,而与此同时,小刘的老婆刘嫂知道小刘的品性&…

牛客练习赛50-记录

正题 比赛链接:https://ac.nowcoder.com/acm/contest/1080#question 成绩 本届 升高二届 总结 以后还是不要写太多自己不擅长的写法,空间要多检查,不要像个傻逼一样啥都写错。 尽量不要为了省一点空间和时间写一些不舒服的东西,尽量在能…

物联网框架ServerSuperIO在.NetCore实现跨平台的实践路线

正所谓天下大势,不跟风不行。你不跨平台,很low嘛。java说:你们能跨嘛,跨给我看看。C#说:不要强人所难嘛。java说:能部署在云上吗?docker?微服务?C#说:不要强人…

使用WebApiClient请求和管理Restful Api

前言本篇文章的内容是WebApiClient应用说明篇,如果你没有了解过WebApiClient,可以先阅读以下相关文章:WebApi client 的面向切面编程我来给.Net设计一款HttpClient.Net45下HttpClient的几个缺陷.net的retrofit--WebApiClient库.net的retrofit…

拥抱.NET Core系列:MemoryCache 缓存选项

MSCache项目MSCache 目前最新的正式版是 2.0.0,预览版是2.1.0,会与 .NETCore 2.1 一起发布。本篇用了2.0.0版本开源在 GitHub 上,仓库地址是:https://github.com/aspnet/CachingNuGet地址为:https://www.nuget.org/pac…

牛客练习赛51-记录

正题 比赛链接:https://ac.nowcoder.com/acm/contest/1083#question 成绩 可怜的zycT3zycT3zycT3被n0n0n0卡了半天,这里感谢一下排雷 总结 比赛状态较好,后面没有T6T6T6的题解 T1:abcT1:abcT1:abc 题目大意 给出一个字符串,求有多少个abc…

Metrics.net + influxdb + grafana 构建WebAPI的自动化监控和预警

前言这次主要分享通过Metrics.net influxdb grafana 构建WebAPI的自动化监控和预警方案。通过执行耗时,定位哪些接口拖累了服务的性能;通过请求频次,设置适当的限流和熔断机制,拦截非法或不合理的请求,保障服务的可用…

EF Core 2.1路线图:视图、GROUP BY和惰性加载

Entity Framework Core一直追随着初始Entity Framework的发展,并不断推陈出新。它首先推出的是对视图的支持,这听起来有些耸人听闻。在即将推出的EF Core 2.1之前,EF Core并未对数据库视图提供官方的支持,也不支持缺少主键的数据库…

计算机网络总结

一、计算机网络体系 (1)OSI分层 (7层) 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。 (2)TCP/IP分层(4层) 网络接口层、 网际层、运输层、 应用层。 &#xff0…

从技术角度讨论微服务

本文希望从技术角度来探讨下微服务,因此,不会过多地谈及如何根据业务进行微服务划分,更多是介绍微服务的相关技术,微服务的业务划分方法可参考“领域驱动设计“相关方法论。微服务的两个程度一、服务化复杂的单体架构会有以下的挑…