C#IQueryable-如何查询另一个列表中的列表

我正在一个项目中显示一个BoardDto,其中包含一个IQueryable的ListDTO。每个ListDTO都包含CardDTO的IQueryable。

我怎样才能使我的BoardDto对象加载所有ListDtos,但仅使用其卡片where CardType = 1

public class BoardDTO
{
        public int BoardId { get; set; }
        public string Nome { get; set; }
        public IQueryable<BoardListDTO> Lists { get; set; }
}

public class BoardListDTO
{
        public int BoardListId { get; set; }
        public string Name { get; set; }
        public IQueryable<CardDTO> Cards { get; set; }
}

public class CardDTO
{
        public long CardId { get; set; }
        public CardType Type { get; set; }
}

编辑

下面的图像说明了项目必须如何构成DTO。

C#IQueryable-如何查询另一个列表中的列表

解决方案

这解决了我的问题:

var query = _context.Boards
                    .AsnoTracking()
                    .ProjectTo<BoardDto>(_mapper)
                    .Where(x => x.BoardId == id)
                    .Select(x => new BoardDto
                             {
                                BoardId = x.BoardId,Name = x.Name,Lists = x.Lists.Select(list => new BoardListSearchDTO
                                                {
                                                    Cards = list.Cards.Where(x => x.Type == 1),}).FilterLists(filterListsBy,listSearchValue)
                                            });
adi2589900 回答:C#IQueryable-如何查询另一个列表中的列表

分开您的担忧。实体代表领域模型。 DTO代表视图或消费者模型。尽管EF广泛处理IQueryable,但您的消费者通常不需要IQueryable,但是大多数时候他们只需要能够枚举结果,因此IEnumerable就足够了。即使在实体中,我也不用IQueryable表示实体之间的关系,而是使用ICollection

IQueryable是一种结构,用于指示应将Linq表达式传递给数据源。对于允许Linq表达式转换为SQL的EF Linq操作。在处理消费返回的数据时,如果需要进一步过滤或转换结果,则可以对IEnumerable等使用Linq。永远不要真正将实体传递到其DbContext范围之外,因为像延迟加载这样的功能要求DbContext保持活动状态,并且您不能可靠地假设延迟加载永远不会被使用中的视图或序列化器等触发。实体是数据状态,视图状态应保持独立。

给定一个由Boards,BoardLists和Cards组成的实体的域模型,我的实体将类似于:

public class Board
{
    public int BoardId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<BoardList> Lists { get; set; } = new List<BoardList>();
}

public class BoardList
{
    public int BoardListId { get; set; }
    public string Name { get; set; }
    public Virtual ICollection<Card> Cards { get; set; } = new List<Card>();
}

public class Card
{
    public long CardId { get; set; }
    public CardType Type { get; set; }
}

实体通常会反映基础表中的所有数据以及实体之间的关系。子集合被声明为virtual,以在需要时容纳延迟加载,并初始化为新集合。这可以适应我们想要创建一个新实体并准备好其子集合的情况。

DTO仅代表消费者所需模型中的数据。在这里,我们还考虑了过滤后的数据视图以适合该视图。除了使用ICollection,我们还可以使用IEnumerable。您可以使用ICollectionIList,但是一般建议使用IEnumerable,因为它向使用者说:“这是您可以阅读的一组数据,但是请不要尝试添加,等等。 ”。

public class BoardDTO
{
    public int BoardId { get; set; }
    public string Name { get; set; }
    public IEnumerable<BoardListDTO> Lists { get; set; }
}

public class BoardListDTO
{
    public int BoardListId { get; set; }
    public string Name { get; set; }
    public IEnumerabe<CardDTO> Cards { get; set; }
}

public class CardDTO
{
    public long CardId { get; set; }
    public CardType Type { get; set; }
}

在此示例中,DTO看起来与实体相同。不过,通常情况下,实体表和基础表将包含许多字段,而我们的视图模型或DTO只需几个字段或关系。

在为视图填充DTO集合时,可以使用Select来利用投影。因此,如果要列出所有至少具有1个cardType 1卡的板,然后仅返回其CardType 1卡的那些板:

这是假设CardType被映射为枚举。如果CardType映射到表,那么它还将需要一个实体/ DTO。

var boards = context.Boards
   .Where(b => b.Lists
      .Any(bl => bl.Cards.Any(c => c.CardType == CardTypes.Type1)))
   .Select(b => new BoardDTO
   {
      BoardId = b.BoardId,Name = b.Name,Lists = b.Lists.Select(bl => new BoardListDTO
      {
         BoardListId = bl.BoardListId,Name = bl.Name,Cards = bl.Cards.Where(c => c.CardType == CardTypes.Type1)
            .Select(c => new CardDTO
            {
               CardId = c.CardId,CardType = c.CardType
            }).ToList()
      }).ToList()
   }).ToList()

此示例在实体和DTO之间进行了大量的一对一映射。通常,DTO被展平以表示消费视图可以使用的结构。这可以将消费者模型合并为仅板卡和板卡列表,且板卡列表名称显示在相关卡DTO中。 (因此,董事会DTO只会显示包含其BoardList名称的卡片列表。)

像这样的

DTO / ViewModel对于过滤数据很有用,因为实体应始终反映真实的数据状态,因此您不能仅返回带有某些相关卡的子集的实体。董事会将始终与所有与其关联的董事会列表以及与之关联的所有卡关联。使用DTO和Select,您可以自定义视图/消费者实际需要的数据。

本文链接:https://www.f2er.com/3142233.html

大家都在问