6

I'm working with a Net Core project, using entity framework, mysql database and pomelo framework. I need to perform this query, in order to compare the last X characters of a property in my model, against a pattern:

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

I want to know if there is any SQL RIGHT function equivalent in Entity framework Core.

Thanks in advance

2
  • Does Where(c => c.CarName.EndsWidth(pattern)) works? If it does not, what is the error message you get? Commented Sep 6, 2018 at 23:39
  • I need to compare the last X characters with the pattern. Example: CarName = "99114". If X = 3 and pattern = "%11%", then the item should be included in the results. But, if CarName="911", X = 1 and pattern = "%11%", the item should be excluded from the results. Using EndsWith would consider "911" as a valid result Commented Sep 6, 2018 at 23:49

2 Answers 2

15

Update (EF Core 5.0+):

EF Core 5.0 introduces IsBuiltIn property on DbFunctionAttribute and IsBuiltIn(bool) fluent API, so providing translation is no more necessary. The minimal mapping is the same as in EF Core 2.x, just

[DbFunction("RIGHT", "")]

is replaced with

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

EF Core 5 also allows Configuring nullability of user-defined function based on its arguments, but it can only be done fluently, so you might consider using explicit mapping rather than generic code. e.g.


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);
    }
}

Update (EF Core 3.0+):

Starting with Ef Core 3.0, empty string schema is treated the same as null, i.e. prepends the default schema to to function name. This way, in case if you want to add built-in function, you have to provide "translation" (weird decision).

So you need to add

using Microsoft.EntityFrameworkCore.Query.SqlExpressions;

and modify the code as follows

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

Original:

Since currently there is neither CLR string nor EF.Functions method called Right, the answer is that EF Core currently does not provide equivalent of SQL RIGHT function.

Fortunately EF Core allows you to add it using the EF Core 2.0 introduced Database scalar function mapping.

For instance, add the following class:

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);
        }
    }
}

(Later on you can add more functions like this if needed).

Then add call to Register from your context OnModelCreating override:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // ...
    MyDbFunctions.Register(modelBuilder);
    // ...
}

And you are done. Now you should be able to use the desired:

_context.Cars
.Where(c => EF.Functions.Like(c.CarName.ToString().Right(5), pattern))
.ToList();
Sign up to request clarification or add additional context in comments.

8 Comments

This is definetly the right answer. I tested it and worked as expected. Thank you!!!
This gives me the following error: Cannot find either column "dbo" or the user-defined function or aggregate "dbo.RIGHT", or the name is ambiguous. I use the DbFunction the same way as in your code example. DB - SQL Server.
@VladyslavKolodka Yeah, unfortunately they changed the meaning of "" schema argument in 3.0 and it's no more treated as "no schema". Now one have to provide "translation". I will update the solution when have some time, thanks for pointing that out.
@IvanStoev fixed with this code: modelBuilder .HasDbFunction(typeof(CustomDbFunctions).GetMethod(nameof(Right))!) .HasSchema(null) .HasTranslation(args => SqlFunctionExpression.Create("RIGHT", args, typeof(string), null));
@VladyslavKolodka Something like that. Looks like HasSchema(null) is not needed, just HasTranslation.
|
-1

Use the following:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.