假设我的代码如下:
public void TestWhenSqlFires()
{
var db = new Db(); // EF DbContext
var items = db.SimpleObjects; // SimpleObject implements interface IId
var byId = WhereId(items, 1);
var array = byId.ToArray();
}
protected IEnumerable<IId> WhereId(IEnumerable<IId> items, int id)
{
return items.Where(i => i.Id == id);
}
在TestWhenSqlFires()的哪一行,SQL实际上是针对数据库运行的吗?
(这是一个从this answer)
的评论中分离出来的问题答案 0 :(得分:1)
找出并测试自己的一种方法:
打开SQL Server Management Studio,打开一个新查询,选择将运行的数据库EF并运行此查询:
SELECT top 10 deqs.last_execution_time AS [Time], dest.TEXT AS [Query]
FROM sys.dm_exec_query_stats AS deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest
ORDER BY deqs.last_execution_time DESC
这将告诉您过去针对数据库运行的10个查询。
在TestWhenSqlFires()的第一行设置一个断点,运行你的代码,然后在单步执行每一行后运行上面的查询。你会发现:
// C# Line 1
var db = new Db();
--SQL Line 1
SELECT TABLE_SCHEMA SchemaName, TABLE_NAME Name FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
// C# Line 2
var items = db.SimpleObjects;
--SQL Line 2
SELECT COUNT(*) FROM [sys].[databases] WHERE [name]=@1
SELECT [GroupBy1].[A1] AS [C1] FROM (
SELECT COUNT(1) AS [A1] FROM [dbo].[__MigrationHistory] AS [Extent1]
) AS [GroupBy1]
(@1 nvarchar(4000))SELECT TOP (1) [Project1].[C1] AS [C1],
[Project1].[MigrationId] AS [MigrationId],
[Project1].[Model] AS [Model] FROM (
SELECT [Extent1].[MigrationId] AS [MigrationId],
[Extent1].[Model] AS [Model], 1 AS [C1]
FROM [dbo].[__MigrationHistory] AS [Extent1]
) AS [Project1] ORDER BY [Project1].[MigrationId] DESC
// C# Line 3
var byId = WhereId(items, 1);
--SQL Line 3
// C# Line 4
var array = byId.ToArray();
--SQL Line 4
SELECT [Extent1].[Id] AS [Id], [Extent1].[Stuff] AS [Stuff]
FROM [dbo].[SimpleObject] AS [Extent1]
最终的SQL查询是EF实际获取数据。先前的查询只是预热 - 验证数据库是否存在,是否正在使用EF5迁移历史记录,并且它与当前的迁移历史记录哈希匹配。
所以答案是 - 调用.ToArray()
之后的第4行(或任何枚举集合的调用,如.ToList(),foreach等)。值得注意的是,将其传递给接受IEnumerable的方法,即使涉及到特定的Generic,也不会枚举该集合,因此不会在必要时提前释放SQL。