-
-
Notifications
You must be signed in to change notification settings - Fork 234
Description
1. Description
Using the example from the documentation page to generate 'Like' conditions results in an exception:
System.Linq.Dynamic.Core.Exceptions.ParseException: "No applicable method 'Like' exists in type 'DynamicFunctions'"
TLDR my Workaround: The string methods
.StartsWith
,.EndsWith
,.Contains
work fine and EFCore can translate them to like-conditions.
2. Any further technical details
-
You might want to add in the documentation that that for using the
DynamicFunctions.Like
the nugetMicrosoft.EntityFrameworkCore.DynamicLinq
is required. Without that, the example returnsSystem.Linq.Dynamic.Core.Exceptions.ParseException: "Type 'DynamicFunctions' not found"
-
Looking into DynamicFunctions.cs, I am not sure why the Like-methods are limited to .Net 2.0 and 2.1? I guess heres the root of the exception because im using .net8 so the methods are not available?
-
But the previous point does not matter, because when using
EF.FunctionsLike
directly with a CustomTypeProvider it leads to the next exception:System.Linq.Dynamic.Core.Exceptions.ParseException: "No applicable method 'Like' exists in type 'DbFunctions'".
. When you look into DbFunctions.cs there is actually no Like-Method, because it is an extension method in DbFunctionsExtensions.cs
3. Workarounds
I found two workarounds to achive my goal, where my goal:
- I dont know when EFCore added support for
.StartsWith
,.EndsWith
,.Contains
, but they just work! So there is no need for me to use CustomTypes :) - If someone still needs other EF.Functions, you have to create a custom class that redirects to the EF.Functions like DynamicFunctions.cs and it will wok again.
3. Fiddle or Project
Heres the code with comments to show all the information from above.
// Vanilla approach of generating a Like-condition with EFCore.
var context = new CustomContext();
var example1 = context.Cars.Where(c => EF.Functions.Like(c.Brand, "%FooBar%"));
Console.WriteLine(example1.ToQueryString());
Console.WriteLine();
// Workaround to make EF.Functions work again.
// The 'CustomTypeProvicer' has a Like-method like 'DynamicFunctions'
var config3 = new ParsingConfig();
config3.ResolveTypesBySimpleName = true;
config3.CustomTypeProvider = new CustomTypeProvicer(config3);
var example4 = context.Cars.Where(config3, "CustomTypeProvicer.Like(Brand, \"%t%\")");
Console.WriteLine(example1.ToQueryString());
Console.WriteLine();
// Workaround of generating Like-condtions directly
var example5 = context.Cars.Where("Brand.Contains(\"FooBar\")");
Console.WriteLine(example5.ToQueryString());
Console.WriteLine();
var example6 = context.Cars.Where("Brand.StartsWith(\"FooBar\")");
Console.WriteLine(example6.ToQueryString());
Console.WriteLine();
var example7 = context.Cars.Where("Brand.EndsWith(\"FooBar\")");
Console.WriteLine(example7.ToQueryString());
Console.WriteLine();
// Unable to find the 'Like'-method because im using an unsuported .net version?
// Comment this block to go to the next block.
var config1 = new ParsingConfig { ResolveTypesBySimpleName = true };
var example2 = context.Cars.Where(config1, "DynamicFunctions.Like(Brand, \"%t%\")");
Console.WriteLine(example1.ToQueryString());
Console.WriteLine();
// Unable to find the 'Like'-method because it is an extension method?
var config2 = new ParsingConfig();
config2.ResolveTypesBySimpleName = true;
config2.CustomTypeProvider = new CustomTypeProvicer(config2);
var example3 = context.Cars.Where(config2, "EF.Functions.Like(Brand, \"%t%\")");
Console.WriteLine(example1.ToQueryString());
Console.WriteLine();
public class Car
{
public int Id { get; set; }
public string Brand { get; set; }
}
public class CustomTypeProvicer(ParsingConfig config)
: DefaultDynamicLinqCustomTypeProvider(config)
{
public override HashSet<Type> GetCustomTypes()
=> [typeof(EF), typeof(CustomTypeProvicer)];
public static bool Like(string? matchExpression, string? pattern)
=> EF.Functions.Like(matchExpression, pattern);
}
public class CustomContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
=> builder.UseSqlite(@"Data Source=.\data.db;");
}