如何将Linq结果转换为DTO类对象而无需迭代

本文关键字:对象 迭代 DTO Linq 结果 转换 | 更新日期: 2023-09-27 18:01:33

我正在构建一个Web API项目,该项目将提供给第三方,也由我自己的Web应用程序使用。Web API方法将返回复杂类型/对象的JSON表示。这些是预定义的类,我可以让第三方使用,这样他们就可以理解数据是如何结构化的,并可以反序列化JSON。我将把这些类称为DTO类,直到有人纠正我。

我有以下自动生成的实体模型(从数据库)好吧,这是用户类无论如何与扫描表的关系(关系可以忽略为这个问题的目的)…

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查询结果映射到DTO类)。

我不确定我应该在哪里/如何实现IEnumerable以启用我的对象上的这种类型的Linq查询,并且我也不确定如何编写类似于上述参考问题中的查询,但对于我的更简单的场景。

提前感谢您的帮助。

注:请忽略的事实,我是通过Web API暴露用户名和密码,我也返回所有用户一次。以上是我的代码的简化版本,用于解决这个问题。

如何将Linq结果转换为DTO类对象而无需迭代

完整的方法可以是:

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()方法时。

您可以使用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();
}

如果我们使用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();
    }
}

在我的查询中,我有多个孩子的父表。

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

当我在linq查询中使用ToList()时,它给出了错误。现在我在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查询的结果集