如何仅在Entity Framework 6.1中加载子对象的某些字段?

Jim*_*Jim 5 c# linq-to-entities entity-framework entity-framework-6

我的工作有两个类的模型,Product和Transaction.

public class Product
{
    [DataMember]
    public Guid ProductId {get; set;}

    [DataMember]
    public virtual ICollection<Transaction> Transactions { get; set; }
}

public class Transaction
{
    [DataMember]
    public Guid TransactionId {get; set;}

    [DataMember]
    public DateTimeOffset Date { get; set; }

    [DataMember]
    public String Customer { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如何进行检索产品及其交易日期的查询?我试过类似的东西

var product = db.Products.Include(p => p.Transactions.Select(t => new { t.Date })).Where(p => p.ProductId = productId);
Run Code Online (Sandbox Code Playgroud)

但它引发了一个例外:

Include路径表达式必须引用在类型上定义的导航属性.使用虚线路径作为参考导航属性,使用Select运算符作为集合导航属性

编辑以澄清:我想要实现的是实际上没有加载 TransactionId和Customer何时Transaction加载.

Eld*_*dho 8

你也可以尝试匿名投影

var product = db.Products.Where(p => p.ProductId = productId)
                         .Select(pr=> new 
                         {
                           product = pr,
                           transactionDates = pr.Transactions.Select(tr=>tr.Date),
                         }.ToList();
Run Code Online (Sandbox Code Playgroud)


oct*_*ccl 5

为了实现您的需求,除了将查询投影到匿名类型或DTO之外别无选择.正如您所看到的,在Include扩展方法中,您只需指定要加载的相关实体,该实体将在具有表的内部联接中转换(或多个联接,请参阅引用链接中的" 备注"部分),但这不是意味着您将从相关实体加载所有属性.如果您调用 Select方法,您可以选择要投影的列,但不能使用实体类型投影Linq to Entities查询,则必须使用我在上面评论的两个选项之一.所以,我的建议是在业务逻辑层创建一组类(DTO)来投影查询结果,例如:

 public class ProductDTO
 {
    [DataMember]
    public Guid ProductId {get; set;}
    [DataMember]
    public virtual IEnumerable<DateTime> TransactionDates { get; set; }
 }
Run Code Online (Sandbox Code Playgroud)

之后你可以这样做:

var product = db.Products.Where(p => p.ProductId = productId)
                         .Select(pr=> new ProductDTO
                         {
                           ProductId = pr.ProductId,
                           TransactionDates = pr.Transactions.Select(tr=>tr.Date),
                         }.ToList();
Run Code Online (Sandbox Code Playgroud)

Include在这种情况下,请参阅我不需要调用扩展方法,因为在Select我从Transactions表中投射一列.在这一点上,数据仍未加载,您只是定义了一个linq查询,后来将其转换为sql.当发生这种情况时?,当你调用ToList扩展方法时.

作为最后的建议,我建议你看看Automapper.将实体与各自的DTO映射后,您的查询可能是这样的:

var product = db.Products.Where(p => p.ProductId == productId)
                         .ProjectTo<ProductDTO>()    
                         .ToList();
Run Code Online (Sandbox Code Playgroud)

有关ProjectTo此链接中的扩展方法的更多信息