实体框架核心中等效的 SQL RIGHT 函数

Posted

技术标签:

【中文标题】实体框架核心中等效的 SQL RIGHT 函数【英文标题】:SQL RIGHT function equivalent in Entity framework Core 【发布时间】:2019-02-12 06:17:08 【问题描述】:

我正在处理一个 Net Core 项目,使用实体框架、mysql 数据库和 pomelo 框架。我需要执行此查询,以便将模型中属性的最后 X 个字符与模式进行比较:

_context.Cars
.Where(c => EF.Functions.Like(c.CarName.ToString().Right(5), pattern))
.ToList();

我想知道Entity framework Core中是否有任何等效的SQL RIGHT函数。

提前致谢

【问题讨论】:

Where(c => c.CarName.EndsWidth(pattern)) 有效吗?如果没有,您收到的错误信息是什么? 我需要将最后 X 个字符与模式进行比较。示例:汽车名称 = “99114”。如果 X = 3 且模式 = "%11%",则该项目应包含在结果中。但是,如果 CarName="911"、X = 1 且模式 = "%11%",则该项目应从结果中排除。使用 EndsWith 会将“911”视为有效结果 【参考方案1】:

更新(EF Core 5.0+):

EF Core 5.0 在 DbFunctionAttributeIsBuiltIn(bool) fluent API 上引入了 IsBuiltIn 属性,因此不再需要提供翻译。最小映射与 EF Core 2.x 中的相同,只是

[DbFunction("RIGHT", "")]

替换为

[DbFunction("RIGHT", IsBuiltIn = true, IsNullable = true)]

EF Core 5 也允许Configuring nullability of user-defined function based on its arguments,但只能流畅地完成,因此您可以考虑使用显式映射而不是通用代码。例如


public static class MyDbFunctions

    public static string Right(this string s, int length)
        => throw new InvalidOperationException();

    public static void Register(ModelBuilder modelBuider)
    
        var fb = modelBuilder.HasDbFunction(() => Right(default, default))
            .HasName("RIGHT").IsBuiltIn(true).IsNullable(true);
        fb.HasParameter("s").PropagatesNullability(true);
    


更新(EF Core 3.0+):

从 Ef Core 3.0 开始,空字符串模式被视为与 null 相同,即将默认模式添加到函数名称。这样,如果你想添加内置功能,你必须提供“翻译”(奇怪的决定)。

所以你需要添加

using Microsoft.EntityFrameworkCore.Query.SqlExpressions;

并修改代码如下

modelBuider.HasDbFunction(dbFunc).HasTranslation(args =>
    SqlFunctionExpression.Create(dbFunc.Name, args, dbFunc.ReturnType, null));                    

原文:

由于目前既没有 CLR string 也没有 EF.Functions 方法称为 Right,答案是 EF Core 目前不提供等效的 SQL RIGHT 函数。

幸运的是,EF Core 允许您使用引入的 EF Core 2.0 Database scalar function mapping 添加它。

例如,添加以下类:

using System;
using System.Linq;

namespace Microsoft.EntityFrameworkCore

    public static class MyDbFunctions
    
        [DbFunction("RIGHT", "")]
        public static string Right(this string source, int length)
        
            if (length < 0) throw new ArgumentOutOfRangeException(nameof(length));
            if (source == null) return null;
            if (length >= source.Length) return source;
            return source.Substring(source.Length - length, length);
        

        public static void Register(ModelBuilder modelBuider)
        
            foreach (var dbFunc in typeof(MyDbFunctions).GetMethods().Where(m => Attribute.IsDefined(m, typeof(DbFunctionAttribute))))
                modelBuider.HasDbFunction(dbFunc);
        
    

(稍后您可以根据需要添加更多类似的功能)。

然后从您的上下文 OnModelCreating 覆盖添加对 Register 的调用:

protected override void OnModelCreating(ModelBuilder modelBuilder)

    // ...
    MyDbFunctions.Register(modelBuilder);
    // ...

你就完成了。现在您应该可以使用所需的:

_context.Cars
.Where(c => EF.Functions.Like(c.CarName.ToString().Right(5), pattern))
.ToList();

【讨论】:

这绝对是正确的答案。我对其进行了测试并按预期工作。谢谢!!! 这给了我以下错误:找不到列“dbo”或用户定义的函数或聚合“dbo.RIGHT”,或者名称不明确。我使用 DbFunction 的方式与您的代码示例相同。数据库 - SQL Server。 @VladyslavKolodka 是的,不幸的是,他们在 3.0 中改变了 "" 模式参数的含义,它不再被视为“无模式”。现在必须提供“翻译”。有时间我会更新解决方案,谢谢指出。 @IvanStoev 使用此代码修复:modelBuilder .HasDbFunction(typeof(CustomDbFunctions).GetMethod(nameof(Right))!) .HasSchema(null) .HasTranslation(args => SqlFunctionExpression.Create("RIGHT ", args, typeof(string), null)); @VladyslavKolodka 类似的东西。看起来不需要HasSchema(null),只需HasTranslation【参考方案2】:

使用以下内容:

_context.Cars.Where(w => DbFunctions.Right(w.CarName,5)==pattern).ToList();

【讨论】:

以上是关于实体框架核心中等效的 SQL RIGHT 函数的主要内容,如果未能解决你的问题,请参考以下文章

实体框架 DbContext 执行的日志查询

原始 SQL 查询和实体框架核心

在 sql server json 列中搜索并使用实体框架核心使用它

csharp 实体框架核心 - SQL查询控制台日志记录

实体框架核心中的截断表

如何使用 C# 代码部分中的 SQL 函数使用 MVC 4 中的实体框架