问题
Suppose I have code like:
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);
}
At what line in TestWhenSqlFires() will SQL actually be run against the database?
(This is a question that spun off from comments on this answer)
回答1:
One way to find out and test for yourself:
Open SQL Server Management Studio, open a new query, select the database EF will be running against and run this query:
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
This tells you the past 10 queries that have run against the database.
Set a breakpoint on the first line of TestWhenSqlFires(), run your code, then run the above query after stepping over each line. You'll find:
// 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]
The final SQL query is EF actually fetching the data. The prior queries are just it warming up - verifying the database exists, that it's using EF5 Migration History, and that it matches the current Migration History hash.
So the answer is - the 4th line, after .ToArray()
is called (or any call that enumerates the collection, like .ToList(), foreach, etc). Notably passing it to a method that accepts IEnumerable, even if there's a specific Generic involved, does not enumerate the collection, and so does not fire off SQL any earlier than necessary.
来源:https://stackoverflow.com/questions/15893180/when-exactly-does-entity-framework-fire-a-sql-command