当被选为对象时;Linq To SQL是否仍然执行SQL查询中的逻辑
本文关键字:SQL 执行 查询 是否 对象 被选为 To Linq | 更新日期: 2023-09-27 18:18:10
假设我有以下简化的Linq查询,它将使用LinqToSQL对数据库运行:
public IEnumerable<MembershipDto> GetAllUserMemberships()
{
return (from m in _workspace.GetDataSource<UserMembership>()
join g in _workspace.GetDataSource<Group>()
on m.GroupID equals g.GroupID
join u in _workspace.GetDataSource<User>()
on m.UserID equals u.UserID
select
new MembershipDto
{
GroupID = g.GroupID,
GroupName = g.Name,
UserID = u.UserID,
UserName = u.Name
}
).Distinct()
.OrderBy(x => x.GroupName)
.ThenBy(x => x.UserName);
}
出于性能考虑,我希望这个查询尽可能多地在生成的SQL查询中运行;然而,我希望在Linq中维护业务逻辑,以便可以轻松地进行单元测试。
我的问题是,我不确定上面的查询停止在SQL中执行,并开始在内存中操作。
我的假设是,一旦数据被选择到new MembershipDto
,它不再是在SQL中进行;因此,后续的OrderBy()
、ThenBy()
和Distinct()
操作都发生在内存中。
但是OrderBy()
产生的是IOrderedQueryable
类型的集合,而不是IOrderedEnumerable
类型的集合;这表明,查询可能仍然在SQL中完整地执行。
是我的假设是正确的,还是整个查询转换成SQL,如果是这样,为什么是这种情况?
看看生成的SQL。我很确信你的斜体假设是错误的。LINQ to SQL提供程序将认识到您的OrderBy
、ThenBy
和Distinct
操作只对SQL结果执行,因此它在将它们反序列化为对象之前完成对您选择的行的操作。只有当你试图对执行时数据库不可用的值进行操作时,查询的那一部分才会由LINQ to Objects执行。
如果在你的初始化器中你设置了一些属性的值,在查询结果中不可用,然后在OrderBy
子句中使用它,它肯定会在内存中进行排序,因为没有其他方法。在本例中,select被转换为SQL SELECT
,然后像往常一样调用OrderBy
和Distinct
。将所选内容转换为对象的操作完全独立于选择数据库中的列。对于SQL提供程序,您的查询与简单的选择语句没有什么不同,它构建一个表达式树,并在执行时将它可以转换为SQL。
我相信您发布的所有代码将被转换成sql。MembershipDto()构造将映射到一个select语句。
当你的函数强制转换为IEnumerable并执行枚举器时,你将"退出"Linq to Sql并"进入"Linq to Objects。
如果你正在使用Linq to Sql进行开发,那么你绝对有必要拥有自己测试的工具。
我推荐LINQPad。你用c#编写代码,它会显示生成的SQL。
另一个解决方案是在数据上下文中记录生成的SQL:
#if DEBUG
/// <summary>
/// Code which runs when the data context is created; called from the constructor
/// </summary>
/// <remarks>Adds console and/or ASP.NET trace logger in DEBUG builds only</remarks>
partial void OnCreated()
{
this.DebugBuildLogging();
}
#endif
我还建议读一本关于LINQ的好书。你会得到多次的奖励。