Подтвердить что ты не робот

Как преобразовать результаты Linq в объект класса DTO без итерации

Я создаю проект веб-API, который будет доступен для сторонних разработчиков, а также будет использоваться моим собственным веб-приложением. Методы Web API возвратят JSON-представления сложных типов/объектов. Это заранее определенные классы, которые я могу предоставить сторонним разработчикам, чтобы они понимали, как структурированы данные и могут десериализовать JSON. Я буду относиться к этим классам как к классам DTO, пока кто-то не поправит меня.

У меня есть следующая автоматически сгенерированная модель сущности (из базы данных), так это класс User в любом случае с отношением к таблице Scan (отношение может быть проигнорировано для целей этого вопроса)...

public partial class User
{
    public User()
    {
        this.Scans = new HashSet<Scan>();
    }

    public int Id { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public bool Active { get; set; }

    public virtual ICollection<Scan> Scans { get; set; }
}

И следующий класс DTO, который я хотел бы вернуться на уровень представления в виде списка (я не думаю, что должен использовать IEnumerable для презентации для бизнеса?).

public class User
{
    public int Id;
    public string Username;
    public string Password;
    public bool Active;
}

Мой бизнес-уровень для этого компонента в настоящее время выглядит ниже. Используя Linq, чтобы получить пользователей из базы данных, а затем проанализировать результаты и вернуть список < > из пользователей POCO.

public List<User> Get()
{
    List<User> userList = new List<User>();

    using (var db = new MyContext())
    {
        var query = from u in db.Users
                    orderby u.FirstName
                    select u;

        foreach (var item in query)
        {
            User user = new User();
            user.Id = item.pkUser;
            user.Username = item.Username;
            user.Password = item.Password;
            user.Active = item.Active;

            userList.Add(user);
        }
    }

    return userList;
}

Анализ результатов, подобных этому, кажется неэффективным, и я видел, что вы можете делать такие вещи в запросе Linq без итерации (например, ответ в этом вопросе Сопоставление Linq Query результаты в класс DTO).

Я не уверен, где/как я должен реализовать IEnumerable, чтобы включить этот тип запроса Linq для моих объектов, а также не знаю, как написать запрос, аналогичный запросу в упомянутом выше вопросе, но для моего более простой сценарий.

Заранее благодарим за помощь.

P.S. Пожалуйста, проигнорируйте тот факт, что я просматриваю имя пользователя и пароль через веб-API, а также что я возвращаю всех пользователей сразу. Выше приведен упрощенный вариант моего кода для этого вопроса.

4b9b3361

Ответ 1

Полный метод может быть:

public List<User> Get()
{
    using (var db = new MyContext())
    {
        return (from u in db.Users
                orderby u.FirstName
                select new User()
                {
                    Id = u.pkUser,
                    Username = u.Username,
                    Password = u.Password,
                    Active = u.Active
                }).ToList();
    }
}

Вы сказали, что хотите получить результат "без итерации". Использование LINQ также не устраняет итерацию. Вы не делаете этого в своем коде, но это действительно происходит, когда вы вызываете метод ToList().

Ответ 2

Вы можете использовать LINQ to Objects для преобразования:

using (var db = new MyContext())
{
    var query = from u in db.Users
                orderby u.FirstName
                select u;

    return query.AsEnumerable().Select(item => 
                 new User 
                     { 
                        Id = item.pkUser,
                        Username = item.Username,
                        Password = item.Password,
                        Active = item.Active
                     }).ToList();
}

Ответ 3

Мы можем получить действительно компактный, если мы используем AutoMapper.

Загрузите карту в свой репозиторий:

Mapper.CreateMap<AutoGenNamespace.User, DtoNamespace.User>();

Тогда это довольно просто (и нет ничего плохого в возвращении IEnumerable).

public IEnumerable<User> Get()
{
    using (var db = new MyContext())
    {
        return (from u in db.Users
                orderby u.FirstName
                select Mapper.Map(u)).AsEnumerable();
    }
}

Ответ 4

В моем запросе у меня есть родительская таблица с несколькими дочерними элементами.

public class TeamWithMembers
        {
            public int TeamId { get; set; }
            public string TeamName { get; set; }
            public string TeamDescription { get; set; }
            public List<TeamMembers> TeamMembers { get; set; }
        }

В этом случае, когда я использовал ToList() в запросе linq, он выдавал ошибку. Теперь я использую анонимный тип в запросе linq и преобразовываю его в следующий запрос, подобный этому

List<TeamModel.TeamWithMembers> teamMemberList = teamMemberQueryResult.AsEnumerable().Select(item =>
new TeamModel.TeamWithMembers() {
    TeamId=item.TeamId,
    TeamName=item.TeamName,
    TeamMembers=item.TeamMembers.ToList()
}).ToList();

Где teamMemberQueryResult - это набор результатов из запроса linq.