【问题标题】:How can I convert Linq results to DTO class object without iteration如何在不迭代的情况下将 Linq 结果转换为 DTO 类对象
【发布时间】:2013-02-27 23:55:48
【问题描述】:

我正在构建一个 Web API 项目,该项目可供第三方使用,也可供我自己的 Web 应用程序使用。 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 类,我想以 List 的形式返回到表示层(我不认为我应该使用 IEnumerable 进行业务到表示?)。

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

我的这个组件的业务层目前如下所示。使用 Linq 从数据库中获取用户,然后解析结果并返回一个 List 的 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 查询中做这种事情而无需迭代(例如这个问题的答案Mapping Linq Query results to a DTO class)。

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

提前感谢您的帮助。

附:请忽略我通过 Web API 公开用户名和密码以及同时返回所有用户的事实。以上是我的代码的简化版本,用于此问题。

【问题讨论】:

  • 无论如何你都会迭代。您可以使用Enumerable.Select 来转换您的列表。

标签: c# .net linq entity-framework


【解决方案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() 方法时它确实发生了。

【讨论】:

  • 我会以最简单、最灵活的答案,穿得最好。谢谢。
  • @Mohammad Dehghan 迭代是否发生在 SQL 服务器上?还是在您客户端的 Linq 库代码中?
  • @Pangamma ToList() 方法调用对从 SQL Server 检索到的结果执行迭代。所以迭代发生在客户端代码中,在ToList() 方法中。 SQL Server(或任何其他数据库引擎)具有自己的排序/过滤/检索数据的机制,可能包含迭代/树遍历/键计算/等。这通常不是任何使用该数据库引擎的应用程序关心的问题。
【解决方案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&lt;AutoGenNamespace.User, DtoNamespace.User&gt;();

    那么就很简单了(返回IEnumerable也没什么问题)。

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

    【讨论】:

    • 我不同意“没什么问题”。 可能出错了! var list = Get(); 然后多次遍历列表。
    • @MD.Unicorn 那么var list = Get().ToList(); 解决了就好了。你知道你通过签名从方法中得到了一个可枚举的返回。
    • 是的,我知道!但是你确定丹知道吗? :-)
    • @MD.Unicorn 他现在应该知道了。
    • 感谢您指出 Romoko,它看起来非常有用(而且简单)但与我的问题相反,类属性实际上并不相同(正如你们可能在最后一个代码块中注意到的那样,数据库在关键字段上使用 pk/fk 前缀)。
    【解决方案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; }
            }
    

    当我在 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 查询的结果集。

    【讨论】:

      猜你喜欢
      • 2011-02-02
      • 1970-01-01
      • 2020-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多