前言

上一节我们讲完原始查询如何防止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() > ? b.Posts.Average(d => d.CommentCount) :
}).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的性能更好。精简的内容,简单的讲解,希望对阅读的您有所帮助,我们明天再会。

EntityFramework Core 2.0自定义标量函数两种方式的更多相关文章

  1. iOS 自定义layer的两种方式

    在iOS中,你能看得见摸得着的东西基本都是UIView,比如一个按钮,一个标签,一个文本输入框,这些都是UIView: 其实UIView之所以能显示在屏幕上,完全是因为它内部的一个图层 在创建UIVi ...

  2. 自定义UITabBar的两种方式

    开发中,经常会遇到各种各样的奇葩设计要求,因为apple提供的UITabBar样式单一,只是简单的"图片+文字"样式,高度49又不可以改变.自定义UITabBar成为了唯一的出路. ...

  3. SpringBoot自定义过滤器的两种方式及过滤器执行顺序

    第一种 @WebFilter + @ServletComponentScan 注解 1.首先自定义过滤器 如下自定义过滤器 ReqResFilter 必须实现  javax.servlet.Filte ...

  4. android 自定义radiogroup的两种方式

    这里先备注下 listview+radiobutton实现  浅显易懂 http://www.haolizi.net/example/view_3312.html 在radiogoup原生态源码的基础 ...

  5. Hibernate查询返回自定义VO的两种方式

    说明:createQuery用的hql语句进行查询,createSQLQuery用sql语句查询: 前者以hibernate生成的Bean为对象装入list返回:后者则是以对象数组进行存储: 一.通过 ...

  6. .Net Core下发送WebRequest请求的两种方式

    1.使用RestSharp.NetCore 2.使用WebApi请求方式

  7. AntDesign VUE:上传组件自定义限制的两种方式(Boolean、Promise)

    AntD上传组件 AntDesign VUE文档 第一种方式 beforeUpload(file) { let isLt = true if (filesSize) { isLt = file.siz ...

  8. EntityFramework Core 2.0执行原始查询如何防止SQL注入?

    前言 接下来一段时间我们来讲讲EntityFramework Core基础,精简的内容,深入浅出,希望为想学习EntityFramework Core的童鞋提供一点帮助. EntityFramewor ...

  9. .NetCore技术研究-EntityFramework Core 3.0 Preview

    前段时间.Net Core 3.0 发布了,Entity Framework Core 3.0 也发布了Preview版.假期用了一上午大致研究了一遍,同时又体验了一把Visual Studio 20 ...

随机推荐

  1. MySQL字符集设置—MySQL数据库乱码问题

    MySQL(4.1以后版本) 服务器中有六个关键位置使用了字符集的概念,他们是:client .connection.database.results.server .system.MySQL有两个字 ...

  2. MySQL 查询最近几天的记录 最近7天的记录 本周内的记录

    本周内:select * from wap_content where week(created_at) = week(now) 查询一天:select * from table where to_d ...

  3. P1345 [USACO5.4]奶牛的电信Telecowmunication

    P1345 [USACO5.4]奶牛的电信Telecowmunication 题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流.这些机器用如下的方式发送电邮 ...

  4. php连接memcahed出现Cannot assign requested address (99)的解决方法

    今天在将服务器合并后,发现php偶尔会报出 Server *.*.*.* (tcp *****) failed with: Cannot assign requested address (99) 的 ...

  5. PID算法

    所谓PID就是比例-积分-微分的英文缩写,但并不是必须同时具备这三种算法,也可以是 PD, PI,甚至只有 P算法控制,下面分别介绍每个参数的含义:首先需要明确一个事实就是,要实现PID算法,必须在硬 ...

  6. 转-HTTP POST GET SOAP本质区别详解

    原文链接:HTTP POST GET SOAP本质区别详解 一 原理区别 一般在浏览器中输入网址访问资源都是通过GET方式:在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认 ...

  7. 安卓和IOS兼容问题

    点击穿透 click延迟 scroll元素临界的bug android screen.w/h 不准 rem不准 scroll时动画失效 animate回调 最小字号限制 不同机型全屏自适应 andro ...

  8. 【转】12 TOP Command Examples in Linux

    12个top命令 1. # top 2. # top,后输入shift+O,在“Current Sort Field:”中选左边的field对应的字母进行排序. 3. # top -u tecmint ...

  9. oracle光标的使用

    以下plsql程序用的scott用户的dept,emp表. 1.光标的使用: --查询并打印员工的姓名名和薪水 /* 光标属性: %found %notfound */ set serveroutpu ...

  10. 基于Java的Arc Engine二次开发的环境的配置

    1.软件准备 ArcGIS for Desktop 10.2, Arc engine, jdk-7u60-windows-i586,Eclipse Mar2 2.软件的安装 2.1 ArcGIS fo ...