Linq to SQL DTO 和复合对象
-
03-07-2019 - |
题
我使用与其他人类似的方法将 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 对象,我返回一个由 User、OrgUnit 和 Role 组成的 DTO Position(底层表是包含 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
我最终没有为我的复杂查询使用过滤器。相反,我向存储库添加了方法,以满足更复杂的查询要求。我觉得这会使系统更易于理解和维护。
其他提示
我已经能够使用类似的方法成功地工作:
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 方法后,我对其应用过滤器。
Linq2SQL只了解设计器生成的对象。嗯,这不完全正确,但足够接近。
因此,当您再次编写Linq查询Linq2SQL对象时,查询将在实际执行时转换为有效的SQL,而不是在写入时。由于您的DTO对象不是Linq2SQL对象,Linq2SQL将不知道如何创建正确的SQL。
如果你想以这种方式保持分离,你必须找到一种只涉及Linq2SQL对象执行查询的方法,并且只将结果映射到你的DTO。
也许您可以将查询方法重写为:
更新:参数必须是类型
Expression<>
,没有必要 返回IQueryable<>
。谢谢 弗雷迪指出。
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)
};
}