C # IQueryable - Как запросить список внутри другого списка - PullRequest
1 голос
/ 07 ноября 2019

Я работаю в проекте, который отображает BoardDto, который содержит IQueryable ListDTO. Каждый ListDTO содержит IQueryable из CardDTO.

Как я могу получить свой объект 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.

enter image description here

Решение

Это решило мою проблему:

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)
                                            });

1 Ответ

0 голосов
/ 08 ноября 2019

Разделите ваши проблемы. Сущности представляют доменные модели. DTO представляют модель представления или потребителя. Хотя EF активно работает с IQueryable, вашим потребителям обычно не требуется IQueryable, в большинстве случаев им просто нужно иметь возможность перечислять результаты, поэтому IEnumerable достаточно. Даже внутри сущностей я не представляю отношения между сущностями с IQueryable, вместо этого я использую ICollection.

IQueryable - это структура, указывающая, что выражения Linq должны быть переданы источникуданные. Для операций EF Linq, позволяющих переводить выражения Linq в SQL. Когда дело доходит до использования данных, которые были возвращены, вы можете использовать Linq против IEnumerable и тому подобное, если вам нужно дополнительно отфильтровать или перевести результаты. Объекты никогда не должны передаваться за пределы их DbContext, поскольку такие функции, как отложенная загрузка, требуют, чтобы DbContext был активен, и вы не можете с уверенностью предполагать, что отложенные нагрузки никогда не будут отключены с помощью потребляющего представления или сериализатора и т. Д. Объекты - это состояние данных, представлениесостояние должно храниться отдельно.

Учитывая доменную модель сущностей, состоящую из плат, списков советов и карт, мои сущности будут выглядеть примерно так:

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. Вы можете использовать ICollection или IList, но, как правило, 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 карта с типом карты 1, а затем вернуть эти платы только с их картами типа 1:

Это предполагает, что CardType отображается как Enum. Если 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()

В этом примере выполняется много преобразований 1: 1 между сущностью и DTO. Часто DTO сглаживаются, чтобы представить структуру, которую может использовать потребительское представление. Это может объединить потребительскую модель только с доской и списком карточек с названием списка досок, отображаемым в DTO соответствующей карточки. (Таким образом, DTO доски будет просто отображать список карт, включающих их имя BoardList.)

DTO / ViewModels, подобные этому, полезны для фильтрации данных, поскольку сущности должны всегда отражать истинное состояние данных, поэтому вы не можете возвращать сущности столько подмножество некоторых связанных карт. Доска всегда ассоциируется со всеми списками, связанными с ней, и со всеми картами, связанными с ними. Используя DTO и Select, вы можете настроить, какие данные действительно нужны представителю / потребителю.

...