c# - LinqKit 嵌套调用 "LINQ to Entities does not recognize the method ' Invoke'"

标签 c# .net linq npgsql linqkit

我不完全理解为什么 select 中的嵌套调用在 LinqKit 中不起作用,想知道是否有人能够帮助我理解。

我的问题:

首先让我列出有效的方法。

假设我们有三个数据库对象:

public class Customer {
     public int Id {get; set;}
     public string Name {get; set;}
     public ICollection<Address> Addresses {get;set;}
}

public class Address {
     public int Id {get;set;}
     public string AddressLine {get;set;}
     public int? Customer_Id { get; set; }
     [ForeignKey("Customer_Id")]
     public virtual Customer Customer {get; set;}
     public int? Coordinates_Id { get; set; }
     [ForeignKey("Coordinates_Id")]
     public virtual Coordinates Coordinates {get; set;}
}

public class Coordinates {
    public int Id {get;set;}
    public double Latitude {get;set;}
    public double Longitude {get;set;}
}

我有三个模型

public class CustomerModel {
   public int Id {get; set;}
   public string Name {get;set;}
   public AddressModel Address {get;set;}
}

public class AddressModel{
  public int Id {get;set;}
  public string AddressLine {get;set;}
  public CoordinatesModel Coordinates {get;set;}
}

public class CoordinatesModel {
    public int Id {get;set;}
    public double Latitude {get;set;}
    public double Longitude {get;set;}
}

所以,现在我想创建可重用的选择表达式。所以我创造了这些

public static Expression<Func<Address, AddressModel>> ToAddressModel = address =>
     new AddressModel {
       Id = address.Id,
       AddressLine = address.AddressLine,
       Coordinates = new Coordinates {
           Id = address.Coordinates.Id,
           Latitude = address.Coordinates.Latitude,
           Longitude = address.Coordinates.Longitude
       }
     };

public static Expression<Func<Customer, CustomerModel>> ToCustomerModel = customer =>
     new CustomerModel {
       Id = customer.Id,
       Name = customer.Name
       Address = customer.Addresses.AsQueryable().Select(ToAddressModel).ToList()
     };

最后,如果我去查询这个,我会写

 dbContext.Customers
    .AsExpandable()
    .Select(ToCustomerModel)
    .ToList();

这按预期工作。但我现在想使 CoordinatesModel 更具可重用性,并制作一个 Expression 来映射它并在 AddressModels Expression 中调用它。

  public static Expression<Func<Coordinates, CoordinatesModel>> ToCoordinates = coordinates =>
      new Coordinates {
           Id = coordinates.Id,
           Latitude = coordinates.Latitude,
           Longitude = coordinates.Longitude
       }

  public static Expression<Func<Address, AddressModel>> ToAddressModel = address =>
     new AddressModel {
       Id = address.Id,
       AddressLine = address.AddressLine,
       Coordinates = ToCoordinatesModel.Invoke(address.Coordinates)
     };

现在如果我查询

  dbContext.Customers
    .AsExpandable()
    .Select(ToCustomerModel)
    .ToList();

它抛出

  System.NotSupportedException: LINQ to Entities does not recognize the method 'CoordinatesModel Invoke[Coordinates,Model](System.Linq.Expressions.Expression`1[System.Func`2[Coordinates,CoordinatesModel]], Coordinates)' method

如果这不正确也没关系,我只是想了解为什么这是不正确的。如果我不针对集合调用(如不确定的导航属性),则嵌套调用没问题。

最佳答案

您必须明确告诉 linq 您正在扩展子表达式 - 就像您在表上使用 .AsExpandable() 时一样 - 在子集中调用时,您必须扩展父级以遍历树并展开子表达式。

所以....您需要做的就是向父表达式添加一个Expand,在这种情况下

public static Expression<Func<Customer, CustomerModel>> ToCustomerModel = customer =>
     new CustomerModel {
       Id = customer.Id,
       Name = customer.Name
       Address = customer.Addresses.AsQueryable().Select(ToAddressModel.Expand()).ToList()
     };

导航属性很好,因为当你展开它的父级时,它会拉入所有子表达式以展开表达式 - 但选择(我只能假设是另一个投影)除非明确声明。

这是文档:http://www.albahari.com/nutshell/linqkit.aspx

关于c# - LinqKit 嵌套调用 "LINQ to Entities does not recognize the method ' Invoke'",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62227180/

相关文章:

c# - System.IndexOutOfRangeException 错误 SQL SELECT 查询无法读取从我的表中选择的数据

c# - 实体 SQL 和 SQL 注入(inject)

c# - 在 c# .net 中覆盖/删除文本文件的内容

c# - 子文件夹中位图的 URI (c# wpf)

c# - 如何在datagridview中捕获删除行(从键盘)?

c# - 未使用的方法和属性对库或可执行文件的影响

.net - C# : How Are Boxed Value Types Handled 中的 Protocol Buffer

c# - 将两个返回 bool 的 LINQ 查询合并为一个返回 bool 的查询?

linq - NPoco/PetaPoco Fetch() 获取所有数据然后过滤客户端是否正常?

c# - 从类型集合中获取公共(public)基类的最简单方法