Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL RIGHT function equivalent in Entity framework Core

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

like image 587
Jawen Avatar asked Sep 06 '18 23:09

Jawen


People also ask

Should I use EF6 or EF core?

Keep using EF6 if the data access code is stable and not likely to evolve or need new features. Port to EF Core if the data access code is evolving or if the app needs new features only available in EF Core. Porting to EF Core is also often done for performance.

What is the alternative for Entity Framework Core?

NHibernate, Entity Framework Core, Hibernate, SQLAlchemy, and Sequelize are the most popular alternatives and competitors to Entity Framework.

Is EF core faster than EF6?

Entity Framework (EF) Core, Microsoft's object-to-database mapper library for . NET Framework, brings performance improvements for data updates in version 7, Microsoft claims. The performance of SaveChanges method in EF7 is up to 74% faster than in EF6, in some scenarios.


1 Answers

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();
like image 109
Ivan Stoev Avatar answered Sep 29 '22 08:09

Ivan Stoev