Linq to SQL DTOs 和复合对象

4

我在使用与其他人类似的方法,将我的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)
             };

核心的DB.Positions是我的Linq职位对象,我返回一个由用户、组织单位和角色组成的DTO职位(基础表是一个带有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 对象直接相关的。

你有什么想法可以让这个工作起来,或者我做错了什么吗?

谢谢。

3个回答

1

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

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

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

也许你可以重新编写查询方法:

更新: 参数必须是 Expression<> 类型,而且没有必要返回一个 IQueryable<>。感谢 Freddy 指出。

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 :) - eglasius
顺便提一下,我已经尝试过这两种方法了,可以看看我的回答 :) - eglasius
弗雷迪,你说得对。我的错,我复制和粘贴太匆忙了 :-( - Thomas Eyde

1

我已经成功地使用了类似的方法:

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

Map 包含:

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

尝试使用这种类型的初始化(而不是构造函数)如何?

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

更新1:这与提到的场景类似,因为:

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

我尝试过类似的映射函数,但我想让我的数据仓库类尽可能精简,然后使用扩展方法将筛选器添加到我的数据仓库实现中。我们有一个测试仓库只使用list<obj>,以及一个用于实际生产代码的sql仓库。 - Devon
我理解,但我的意思是这可能是由于使用构造函数(只是猜测)。请注意,我的映射方法返回一个IQueryable<UserCourseListItem>,这就是为什么我认为过滤器情况是等效的原因。 - eglasius
这会从数据存储中获取所有数据,然后过滤映射的对象吗? - Devon
你所说的“fetch”,是指如果不过滤数据,就可以获取所有数据的IQueryable。当你对其进行过滤时,Linq2Sql会在查询中考虑到这一点,因此你只会得到经过筛选的数据 :) - eglasius

1

最终我没有在复杂查询中使用筛选器。相反,我向存储库添加了适用于更复杂查询需求的方法。我认为这将使系统更易于理解和维护。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接