EF Core 是否可以在针对具有转换的属性的查询中调用方法?

Hol*_*ver 8 c# sql sql-server entity-framework entity-framework-core

假设我想增强一个模型,例如

public class Person
{
    public string Name { get; set; }
    public string Address { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以使用一个复杂的对象Address

public class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

EF Core 非常好地允许使用以下功能HasConversion

modelBuilder.Entity<Person>
            .Property(p => p.Address)
            .HasConversion(addr => addr.ToString(), str => Address.FromString(str));
Run Code Online (Sandbox Code Playgroud)

我什至测试过,这适用于带有==运算符的查询:以下内容将成功转换为 SQL

var whiteHouse = Address.Parse("1600 Pennsylvania Avenue NW");
var matches = from person in people 
              where person.Address == whiteHouse 
              select person;
Run Code Online (Sandbox Code Playgroud)

但是,假设我想在的版本string.Contains上,类似stringAddress

var search = "1600";
var matches = from person in people 
              where person.Address.ToString().Contains(search) 
              select person;
Run Code Online (Sandbox Code Playgroud)

这将导致转换失败。EF Core 是否有任何功能可以映射ToString()方法或以其他方式映射转换为string/的复杂对象VARCHAR,以便我可以编写这样的查询?

Iva*_*oev 9

EF Core 值转换器和 LINQ 查询的问题在于 LINQ 查询针对的是 CLR 实体属性,因此针对的是 CLR 类型而不是提供程序类型。当前EF Core 文档的值转换系统部分的限制部分提到了这一点:

使用值转换可能会影响 EF Core 将表达式转换为 SQL 的能力。对于此类情况,将会记录一条警告。正在考虑在未来版本中删除这些限制。

因此,针对 CLR 类型的查询表达式加上无法转换自定义方法会导致您的问题。从技术上讲,可以添加自定义方法/属性转换,但它非常复杂,因为需要大量非用户友好的基础设施管道代码,这使得在现实生活应用程序开发中几乎无法使用。

但在这种特殊情况下,您知道提供程序类型是string,并且数据库表值是通过ToString方法生成的。所以你只需要让查询使用provider类型即可。您可以通过使用强制转换运算符来做到这一点。

通常,如果已知对象类型之间没有转换,C# 编译器将不允许将它们转换为另一个已知对象类型。但是您可以通过使用“双重转换”技术来欺骗它,首先转换object为所需的类型,然后再转换为所需的类型。幸运的是,EF Core 翻译器支持此类转换并正确(某种程度上)将它们转换为 SQL。我的意思是它CAST在查询中发出不必要的(冗余的),但至少它在服务器端进行翻译和执行。

话虽如此,您的示例的解决方案是

where ((string)(object)person.Address).Contains(search)
Run Code Online (Sandbox Code Playgroud)