Entity Framework 嵌套导航属性计数

5

我有三个模型类

public class Item1{

    public int Id;

    public List<Item2> Item2List { get; set; }
}

public class Item2{
    public int Id;

    //this is the FK
    public int Item1Id {get;set;}

    public Item1 Item1 {get;set;}

    //Not in db. Ignored field in EntityTypeConfiguration
    public int Item3Count;

    public List<Item3> Item3List { get; set; }
}

public class Item3{
    public int Id;

    //this is the FK
    public int Item2Id {get;set;}

    public Item2 Item2 {get;set;}    
}

我希望能够返回Item1列表和相关的Item2列表,并加载与Item2关联的Item3List计数,而不需要加载Item3List。
这是我目前正在进行的操作:
public IEnumerable<Item1> GetItems()
{
    return base.Query().Include(item1 => item1.Item2List.Select(item2 => item2.Item3List)).ToList();
}

这段代码返回了三个对象Item1、Item2和Item3的列表。但我只需要Item3Count中Item3List的计数,而不是整个Item3List列表。我该怎么做?我尝试了下面的代码,但它会出现错误。
return base.Query().Include(item1 => item1.Item2List.Select(item2 => new Item2 {
Item3Count = item2.Item3List.Count()
})).ToList();

Include路径表达式必须引用类型上定义的导航属性。对于引用导航属性,请使用点路径表示;对于集合导航属性,请使用Select运算符。参数名称:路径。

2个回答

3
你想要的是不可能的。当然,在EF LINQ查询中填充一个未映射的属性是不可能的,因为这就是未映射的含义。但你已经知道了这一点。
你真正想做的事情是这样的:
context.Item1s.Select(item1 => new Item1
{
    Id = item1.Id,
    Item2s = item1.Item2List.Select(item2 => new Item2List
    {
        Id = item2.Id,
        Item3Count = item2.Item3List.Count()
    })
})

但 EF 不允许你在 EF 查询中构造实体对象。

其他选择也不是很理想。

你可以构建一个匿名类型的结构...

context.Item1s.Select(item1 => new
{
    Item1 = item1,
    Item2s = item1.Item2List.Select(item2 => new
    {
        Item2 = item2,
        Item3Count = item2.Item3List.Count()
    })
})

...并使用此构建Item1对象列表,每个对象都有其具有Item3Count值的 Item2 的 Item2List 。

更好的方法是使用AutoMapper将实体映射到DTO:

Mapper.CreateMap<Item1,Item1Dto>();
Mapper.CreateMap<Item2,Item2Dto>();

你可以使用AutoMapper的展开特性来填充Item3Count。为此,Item2Dto应该有一个Item3ListCount属性,AutoMapper将把它翻译成Item3List.Count()

谢谢!我不确定是否可能,但这就是我需要知道的。 - codermav

0

你没有使用 ef 约定。请参考 https://msdn.microsoft.com/en-us/data/jj819164.aspx 进行操作。 你需要像这样做:


public class Item1{

  public int Item1Id{get;set;}

  public ICollection<Item2> Item2s{ get; set; }
}

public class Item2{

  public int Item2Id{get;set;}

  //Not in db. Ignored field in mapping
  [NotMapped]
  public int Item3Count => Item3s.Count;

  //this is the FK
  public int Item1Id{get;set;}

  public Item1 Item1 {get;set;}

  public ICollection<Item3> Item3s{ get; set; }
}

public class Item3{
  public int Item3Id;

  //FK
  public int Item2Id {get;set;}

  public Item2 Item2 {get;set;}

}

现在:

public IEnumerable<int> GetCounts()
{
   //get the items1 including its List of item2
   var items1 = base.Query().Include(item1 => item1.Item2s);

   //get the counts
   var counts = items1.Select(item1 => item1.Item2s.Select(item2 => item2.Item3Count));

   //now in counts you have what you want, do what you please with it
   //and return it
   return counts;

}


我没有尝试过这个,但它应该适用于你。


抱歉,我没有发布完整的模型,但是它已经按照您展示的方式设置了外键和导航属性。在entitytypeconfiguration中,“Item3Count”属性被设置为忽略(this.Ignore(t => t.Item3Count))。但是我收到以下错误信息:“指定的包含路径无效。实体类型'Namespace.DataContext.Item2'未声明名称为'Item3Count'的导航属性。”感谢您的帮助! - codermav
我想返回IEnumerable<Item1>而不是IEnumerable<int>。此外,我尝试了您更新的解决方案,但它抛出异常“值不能为null,参数名称为Source”。看起来是因为我们没有获取Item3并直接尝试获取计数,而Item3为null。如果在第一步中获取Item3s,则代码块可以正常工作,但这样做就失去了目的。我正在尝试找到一种方法来返回包括Item2和仅Item3计数的IEnumerbale<Item1>。谢谢您的关注! - codermav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接