Custom ValueConverter from class to string ignores column type and unicode property settings
See original GitHub issueI have created a custom value converter to convert from a class to a string and vice versa. When using this property in a Contains
lambda the SQL generation for the WHERE IN
clause does not take into consideration the property builder extension functions IsUnicode
or HasColumnType
. This results in a SQL statement where a varchar
field is being cast to nvarchar(max)
and the string values in the IN
clause are unicode (N'my string'
).
This is a huge performance hit and I would expect the IsUnicode
and HasColumnType
would be good enough hints for the SQL generation engine to treat the strings as ASCII.
I have also tried adding CustomMappingHints
to the ValueConverter
which did not change the SQL generation at all either.
Steps to reproduce
public class ValueString
{
private readonly string _value;
public ValueString(string value)
{
_value = value;
}
public static implicit operator string(ValueString valueString)
{
return valueString._value;
}
public override bool Equals(object obj)
{
if (!(obj is ValueString valueString))
return false;
return _value == valueString._value;
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public override string ToString()
{
return _value;
}
}
public static class PropertyBuilderExtensions
{
public static PropertyBuilder<ValueString> HasValueStringConversion<ValueString>(this PropertyBuilder<ValueString> propertyBuilder)
{
var converter = new ValueConverter<ValueString, string>(
t => t.ToString(),
s => new ValueString(s));
return propertyBuilder.HasConversion(converter);
}
}
public class MyClass
{
public ValueString Hello { get; set; }
}
public class MyClassEntityConfiguration : IEntityTypeConfiguration<MyClass>
{
public void Configure(EntityTypeBuilder<MyClass> builder)
{
...
builder.Property(e => e.Hello)
.IsUnicode(false)
.HasValueStringConversion();
}
}
Sample call:
context.MyClass.Where(a => list.Contains(a.Hello));
Results in:
SELECT Hello FROM MyClass
WHERE CAST(Hello AS nvarchar(max)) IN (N'sample', N'test')
Further technical details
EF Core version: 3.1.2 Database provider: Microsoft.EntityFrameworkCore.SqlServer v3.1.2 Target framework: .NET Core 3.1 Operating system: Windows 10 Enterprise IDE: Rider
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (2 by maintainers)
Thanks for the assistance, it is working now that the type is changed to
IEnumerable<ValueString>
. I think the implicit conversion betweenValueString
andstring
was causing unnecessary confusion for me on how the compiler would know what to do.I see what you mean. I’ll try that.