我怀疑您可能没有正确使用.Select,因为这正是它的设计目的。
要获取相关的 A 详细信息,无需 B 或 C:
var aDetails = context.As.Select(a => new { a.Id, a.Name }).ToList();
请注意,这将返回一个匿名类型,其中仅包含您想要的字段,在本例中,是来自 A 记录的 ID 和名称。现在,如果您想返回要在视图等中使用的数据,那么您可以定义一个视图模型类来调用 AViewModel,例如使用该 ID 和名称:
var viewModels = context.As.Select(a => new AViewModel{ Id = a.Id, Name = a.Name }).ToList();
人们经常因为试图将实体发送到视图而被抓到。这是一个糟糕的、糟糕的模式,为了避免定义另一个看起来很像实体的 POCO 类,它经常被掩盖。但是,有 2 个非常好的理由应该避免它:信息的安全性和性能。 (概述here)如果你这样做:
var results = context.As.ToList();
甚至
var results = context.As.Select(a => a).ToList();
启用 LazyLoading (EF6) 这将只加载您的 A 记录,而不加载 B 或 C。但是,如果您尝试将这些实体传递回您的客户端,则序列化程序将遍历每个属性,触发 B 和 C 集合上的延迟加载,为每个单独的 A 记录加载每个集合。在返回 A 的集合时,这将比在查询中预先加载 Bs 和 Cs 的情况要糟糕得多,因为如果返回 5x A 记录,延迟加载调用将相当于:
从 B 中选择 AId = 1,从 B 中选择 AId = 2,...
从 C 中选择 AId = 1,从 C 中选择 AId = 2,...
10x 额外的 SQL 语句,而不是在一个初始(更大的)SQL 语句中包含所有相关的 B 和 C 行。您可以通过关闭 EF 延迟加载(关闭代理)来避免此性能陷阱,但随后您将获得不反映实际数据状态的空集合。 (IMO 一个实体应该始终完全代表它的数据状态,不要猜测丢失的数据是否根本没有加载,或者实体实际上没有相关数据。)
扩展Select 如何提高性能;假设您有一组订单,其中包含订单项目列表,并且每个订单都与一个客户相关联。您需要订单编号、订单项目的总成本和客户姓名。您不想为每个订单加载所有订单商品和客户详细信息:
var orderDetails = context.Orders
.Where(o => o.OrderDate >= startDate && o.OrderDate < endDate)
.Select(o => new OrderViewModel
{
OrderId = o.OrderId,
OrderNumber = o.OrderNumber,
CustomerName = o.Customer.FullName,
Total = o.OrderLines.Sum(ol => ol.UnitPrice * ol.Quantity)
}).ToList();
这是 EF 和 Linq 的一个强大功能,有助于确保数据库完成大部分工作并只返回您需要的字段。网络上的数据更少,应用服务器和客户端上的内存使用更少。