【问题标题】:Linq to SQL DTOs and composite objectsLinq to SQL DTO 和复合对象
【发布时间】:2009-03-04 18:15:48
【问题描述】:

我使用与其他人类似的方法将我的 LINQ 对象保存在我的 LINQ 数据提供程序中并返回 IQueryable 以允许过滤等。这适用于通过其 ID 或其他属性过滤简单对象,但我有一个由其他子对象组成的连接表对象的问题

    //CoreDBDataContext db = coreDB;
public IQueryable<DTO.Position> GetPositions()    {
     return from p in coreDB.Positions
         select new DTO.Position
             {
             DTO.User = new DTO.User(p.User.id,p.User.username, p.User.firstName,p.User.lastName,p.User.email,p.User.isActive),
             DTO.Role = new DTO.Role(p.Role.id, p.Role.name, p.Role.isActive),
             DTO.OrgUnit = new DTO.OrgUnit(p.OrgUnit.id,p.OrgUnit.name,p.OrgUnit.isActive)
             };

coreDB.Positions 是我的 Linq Position 对象,我返回一个 DTO Position,它由 User、OrgUnit 和 Role 组成(基础表是具有 UserID、RoleID 和 OrgUnitID 的连接表)

我遇到的问题是,当我尝试在 Iqueryable 上添加过滤器时,我收到一条 SQL 错误,提示我的 DTO.User 对象没有可用的翻译

public static IQueryable<Position> WithUserID(this IQueryable<Position> query, int userID)
    {
        return query.Where(p => p.User.ID == userID);
    }

我完全不知道如何解决这个问题,因为我所有的 Google 结果似乎都是与直接使用生成的 LINQ 对象的人一起工作的

关于如何完成这项工作的任何想法,或者我在这里做错了什么?

谢谢

【问题讨论】:

    标签: linq-to-sql dto separation-of-concerns


    【解决方案1】:

    我已经能够使用类似的方法成功地工作:

    var courses = from c in Map(origCourses)
    where !expiredStatuses.Contains(c.Status)
    select c;
    

    地图在哪里:

        select new UserCourseListItem
        {
            CourseID = c.CourseID,
            CourseName = cm.CourseName,
            CourseType = c.CourseType.Value
            ...
    

    用这种类型的初始化(而不是构造函数)尝试一下怎么样。

    附言。这是一个工作应用程序的一部分,expiredStatuses 甚至与一个复杂的表达式有关。

    更新 1: 与上述场景相比,这类似于,因为:

    • Map 正在返回一个 IQueryable,它是一个 POCO 对象。
    • 在调用返回带有 POCO 对象的 IQueryable 的 Map 方法后,我正在对其应用过滤器。

    【讨论】:

    • 我尝试过类似的映射功能,但我试图让我的数据存储库类尽可能精简,然后使用扩展方法将过滤器添加到我的数据存储库的实现中。我们有一个仅使用 list 的测试存储库,以及一个用于我们实际生产代码的 sql 存储库
    • 我理解,但我的意思是这可能是由于使用了构造函数(只是猜测)。请注意,我的 map 方法返回一个 IQueryable,这就是为什么我认为过滤器情况是等价的。
    • 那么这会从数据存储中获取所有数据,然后过滤映射的对象吗?
    • 你的意思是有一个 IQueryable 如果你不过滤它可以获取所有数据,是的。当你过滤它时,linq2sql 实际上会在查询中考虑它,所以你只会得到过滤后的数据:)
    【解决方案2】:

    Linq2SQL 只理解设计器生成的对象。嗯,这并不完全正确,但已经足够接近了。

    因此,当您针对 Linq2SQL 对象编写 Linq 查询时,查询将在查询实际执行时转换为有效 SQL,而不是在编写时。由于您的 DTO 对象不是 Linq2SQL 对象,因此 Linq2SQL 将不知道如何创建正确的 SQL。

    如果你想保持这种分离,你必须找到一种方法来执行你的查询,只涉及 Linq2SQL 对象,并且只将结果映射到你的 DTO。

    也许您可以将查询方法重写为:

    更新:参数必须是类型 Expression&lt;&gt;,没必要 返回IQueryable&lt;&gt;。谢谢 弗雷迪指出。

    public IEnumerable<DTO.Position> FindPositions(Expression<Func<Position, bool>> criteria)
    {
        return from p in coreDB.Positions
               where criteria.Invoke(p)
               select new DTO.Position
                          {
                              User = new DTO.User(p.User.id, p.User.username, p.User.firstName, p.User.lastName,
                                           p.User.email, p.User.isActive),
                              Role = new DTO.Role(p.Role.id, p.Role.name, p.Role.isActive),
                              OrgUnit = new DTO.OrgUnit(p.OrgUnit.id, p.OrgUnit.name, p.OrgUnit.isActive)
                          };
    }
    

    【讨论】:

    • 但是,为什么要让结果 IQueryable :)
    • 顺便说一句,我已经使用了这两种方法,请参阅我的答案:)
    • 弗雷迪,你是正确的。我的不好,我复制粘贴太仓促了:-(
    【解决方案3】:

    我最终没有为我的复杂查询使用过滤器。相反,我将方法添加到存储库以满足更复杂的查询要求。我觉得这将使系统更易于理解和维护。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-06
      • 2010-09-08
      • 1970-01-01
      • 1970-01-01
      • 2010-12-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-03
      相关资源
      最近更新 更多