Как преобразовать результаты 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, а также что я возвращаю всех пользователей сразу. Выше приведен упрощенный вариант моего кода для этого вопроса.
Ответы
Ответ 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.