question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Expression with value converter could not be translated

See original GitHub issue

I have created a value converter to store a list of strings as a semicolon-separated string and it looks like EF Core can’t translate a LINQ expression to filter these and evaluates it locally.

Is this an example of what’s stated in the limitations section of the docs? Or is there another way for me to have EF translate this WHERE statement correctly (apart from writing raw SQL)?

Use of value conversions may impact the ability of EF Core to translate expressions to SQL. A warning will be logged for such cases. Removal of these limitations is being considered for a future release.

Steps to reproduce

public class Post
{
  public int Id { get; set; }
  public string Title { get; set; }
  public List<string> Labels { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder
    .Entity<Post>()
    .Property(x => x.Labels)
    .HasConversion(
      x => string.Join(';', x),
      x => x.Split(new[] { ';' }).ToList()
    );
}

When executing this query: _dbContext.Set<Post>().Where(x => x.Labels.Contains(".NET CORE")).ToList() I get the following warning:

Microsoft.EntityFrameworkCore.Query:Warning: The LINQ expression 'where {[x].Labels => Contains(".NET CORE")}' could not be translated and will be evaluated locally.
Microsoft.EntityFrameworkCore.Query:Warning: The LINQ expression 'Contains(".NET CORE")' could not be translated and will be evaluated locally.
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (41ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [x].[Id], [x].[Title], [x].[Labels]
FROM [Post] AS [x]

Further technical details

EF Core version: 2.2.6 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET Core 2.2 Operating system: Windows 10 IDE: Visual Studio 2019 16.0

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
MoazAlkharfancommented, Feb 22, 2022

@Schaemelhout

There is a possible workaround to be able to write your query.

First you make your labels into a first class object, and stick an explicit string conversion operator to allow the query code to compile.

public class PostLabels : List<string>
{
    // Add your validation, initialization, overrides, etc..

    // Only to support ef core query.
    public static explicit operator string(UserExternalIds v)
    {
        throw new NotImplementedException();
    }
}

public class Post
{
  public int Id { get; set; }
  public string Title { get; set; }
  public PostLabels Labels { get; set; }
}

Then you would write your query as such.

_dbContext.Set<Post>().Where(x => ((string)x.Labels).Contains(".NET CORE")).ToList()
  1. It compiles because we have the conversion operator above.
  2. Because this is an expression used to translate linq into SQL, the exception won’t be thrown, unless it had to do client side evaluation.
  3. You can only do queries on strings.
0reactions
caztialcommented, Jul 7, 2022

@Schaemelhout

There is a possible workaround to be able to write your query.

First you make your labels into a first class object, and stick an explicit string conversion operator to allow the query code to compile.

public class PostLabels : List<string>
{
    // Add your validation, initialization, overrides, etc..

    // Only to support ef core query.
    public static explicit operator string(UserExternalIds v)
    {
        throw new NotImplementedException();
    }
}

public class Post
{
  public int Id { get; set; }
  public string Title { get; set; }
  public PostLabels Labels { get; set; }
}

Then you would write your query as such.

_dbContext.Set<Post>().Where(x => ((string)x.Labels).Contains(".NET CORE")).ToList()
  1. It compiles because we have the conversion operator above.
  2. Because this is an expression used to translate linq into SQL, the exception won’t be thrown, unless it had to do client side evaluation.
  3. You can only do queries on strings.

Improvement

public class PostLabels : List<string>
{
        public PostLabels() : base()
        {
        }

        public PostLabels(IEnumerable<string> collection) : base(collection)
        {
        }
    
    // Only to support ef core query.
    public static explicit operator string(PostLabels v)
    {
        throw new NotImplementedException();
    }
}

public class Post
{
  public int Id { get; set; }
  public string Title { get; set; }
  public PostLabels Labels { get; set; }
}

and your value Conversation should look like this

 builder.Property(a => a.Tags).HasConversion(
                    i => string.Join(";", i),
                    o => new PostLabels(o.Split(new char[] { ';' }).ToList()));
Read more comments on GitHub >

github_iconTop Results From Across the Web

The LINQ expression could not be translated. Either rewrite ...
The issue is that you are trying to do a string.Contains within an Any expression which EF will choke on trying to compose...
Read more >
LINQ Expression Could not Be Translated - Microsoft Q&A
Hello everyone and thanks for the help in advance. I am creating a MVC application uisng .Net 6 and EF 6 to query...
Read more >
Value Conversions - EF Core
Value converters allow property values to be converted when reading from or writing to the database. This conversion can be from one value...
Read more >
Going down the rabbit hole of EF Core and converting strings ...
I am working on a greenfield project that uses EF Core 6 with AspNetCore 6 at the moment. The project involves exposing a...
Read more >
Entity Framework Core Conversions for Logical Domain ...
NET EF Core Converters to map logical domain types to database columns. ... Value. EndsWith("@example.com"))' could not be translated.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found