【发布时间】:2017-07-25 15:21:57
【问题描述】:
我的目标是以尽可能少的开销查询和映射复杂对象。我正在使用一个包含大量相关表的大型数据库。我正在尝试使用 LINQ 选择和投影来仅选择制作对象所需的必要信息。
这是我最初的查询,速度很快,效果很好。
List<ClientDTO> clientList = dbClients.Select(client =>
new ClientDTO
{
ID = client.ClientID,
FirstName = client.FirstName,
LastName = client.LastName,
//etc....
Products = client.Products
.Select(prod => new ProductDTO
{
ID = prod.ID,
DateOfTransaction = prod.Date,
//etc...
}).ToList(),
Items = client.Items
.Select(item => new ItemDTO
{
ID = item.ID,
Date = item.Date,
//etc...
}
});
请记住,Client 表有 50 多个相关表,因此这个查询非常有效,因为它只选择了我需要创建对象的字段。
现在我需要为这些对象制作映射器,并尝试构建相同的查询语句,但这次使用映射器。这就是我最终得到的结果。
List<ClientDTO> clients = dbClients.ProjectToClientDTO();
使用这些映射器
public static List<ClientDTO> ProjectToClientDTO(this IQueryable<Clients> query)
{
var clientList = query.Select(client => new
{
ID = client.ClientID,
FirstName = client.FirstName,
LastName = client.LastName,
//etc...
Products = client.Products.AsQueryable().ProjectToProductDTO().ToList(),
Items = client.Items.AsQueryable().ProjectToItemDTO().ToList()
}
List<ClientDTO> dtoClientList = new List<ClientDTO>();
foreach (var client in clientList)
{
ClientDTO clientDTO = new ClientDTO();
clientDTO.EncryptedID = EncryptID(client.ID, client.FirstName, client.LastName);
//etc...
clientDTO.Products = client.Products;
clientDTO.Items = client.Items;
}
return dtoClientList;
}
public static IQueryable<ProductDTO> ProjectToProductDTO(this IQueryable<Products> query)
{
return query.Select(prod => new ProductDTO
{
ID = prod.ID,
DateOfTransaction = prod.Date,
//etc...
});
}
public static IQueryable<ItemDTO> ProjectToItemDTO(this IQueryable<Items> query)
{
return query.Select(item => new ItemDTO
{
ID = item.ID,
Date = item.Date,
//etc...
});
}
尝试运行此程序后,我收到以下错误。
LINQ to Entities 无法识别方法“ProjectToProductDTO(IQueryable[Products])”,并且该方法无法转换为存储表达式。"}
我可以让 LINQ 调用这些方法来构建查询吗? 或者有没有更好的方法来查询和映射这些对象,而无需为数百个客户端抓取 50 多个不必要的数据表?
更新
用户 Tuco 提到我可以尝试查看表达式树。在阅读了一段时间后,我想出了这个。
public static Expression<Func<Product, ProductDTO>> test = prod =>
new ProductDTO()
{
ID= prod.ID,
Date= prod.Date,
//etc...
};
就这样使用它。
Products = client.Products.Select(prod => test.Compile()(prod)),
但是运行这个我收到这个错误。
LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”
【问题讨论】:
-
EF 默认不返回所有图表,您必须为每个导航属性使用 Include
-
这不是叫懒加载吗,不是默认开启的吗?
-
是的,但在您请求之前它不会提取数据
-
你要做的事情需要表达式树
-
你为什么“需要”使用映射器?一般来说,您不能将用户定义的函数放入其他查询中,但您可以使用 LINQKit 之类的东西对用户定义的函数进行 lambda 扩展。
标签: c# .net linq linq-to-entities expression-trees