Interest Ask. Taking it to decompiled sources, when compiling the request, this happens:
public static Func<TArg0, TArg1, TResult> Compile<TArg0, TArg1, TResult>(Expression<Func<TArg0, TArg1, TResult>> query) where TArg0 : DataContext { if (query == null) System.Data.Linq.Error.ArgumentNull("query"); if (CompiledQuery.UseExpressionCompile((LambdaExpression) query)) return query.Compile(); else return new Func<TArg0, TArg1, TResult>(new CompiledQuery((LambdaExpression) query).Invoke<TArg0, TArg1, TResult>); }
The UseExpressionCompile method is defined as follows:
private static bool UseExpressionCompile(LambdaExpression query) { return typeof (ITable).IsAssignableFrom(query.Body.Type); }
When evaluating the expression that you defined, this value is false, so the else case is used.
The call is as follows:
private TResult Invoke<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1) where TArg0 : DataContext { return (TResult) this.ExecuteQuery((DataContext) arg0, new object[2] { (object) arg0, (object) arg1 }); }
ExecuteQuery is similar:
private object ExecuteQuery(DataContext context, object[] args) { if (context == null) throw System.Data.Linq.Error.ArgumentNull("context"); if (this.compiled == null) { lock (this) { if (this.compiled == null) this.compiled = context.Provider.Compile((Expression) this.query); } } return this.compiled.Execute(context.Provider, args).ReturnValue; }
In this case, our provider is the SqlProvider class, SqlProvider.CompiledQuery is the class that implements ICompiledQuery. This class is being executed:
public IExecuteResult Execute(IProvider provider, object[] arguments) { if (provider == null) throw System.Data.Linq.SqlClient.Error.ArgumentNull("provider"); SqlProvider sqlProvider = provider as SqlProvider; if (sqlProvider == null) throw System.Data.Linq.SqlClient.Error.ArgumentTypeMismatch((object) "provider"); if (!SqlProvider.CompiledQuery.AreEquivalentShapes(this.originalShape, sqlProvider.services.Context.LoadOptions)) throw System.Data.Linq.SqlClient.Error.CompiledQueryAgainstMultipleShapesNotSupported(); else return sqlProvider.ExecuteAll(this.query, this.queryInfos, this.factory, arguments, this.subQueries); }
SqlProvider.ExecuteAll calls SqlProvider.Execute, which is a pretty big method, so I will post the main points:
private IExecuteResult Execute(Expression query, SqlProvider.QueryInfo queryInfo, IObjectReaderFactory factory, object[] parentArgs, object[] userArgs, ICompiledSubQuery[] subQueries, object lastResult) { this.InitializeProviderMode(); DbConnection dbConnection = this.conManager.UseConnection((IConnectionUser) this); try { DbCommand command = dbConnection.CreateCommand(); command.CommandText = queryInfo.CommandText; command.Transaction = this.conManager.Transaction; command.CommandTimeout = this.commandTimeout; this.AssignParameters(command, queryInfo.Parameters, userArgs, lastResult); this.LogCommand(this.log, command); ++this.queryCount; switch (queryInfo.ResultShape) { case SqlProvider.ResultShape.Singleton: DbDataReader reader1 = command.ExecuteReader(); ... case SqlProvider.ResultShape.Sequence: DbDataReader reader2 = command.ExecuteReader(); ... default: return (IExecuteResult) new SqlProvider.ExecuteResult(command, queryInfo.Parameters, (IObjectReaderSession) null, (object) command.ExecuteNonQuery(), true); } } finally { this.conManager.ReleaseConnection((IConnectionUser) this); } }
Between acquiring and releasing a connection, it runs sql commands. Therefore, I would say that you are right. Contrary to popular belief, compiled requests do not behave the same as uncompiled requests when it comes to deferred execution.
I'm sure you can download the actual source code from MS, but I don’t have it at hand, and Resharper 6 has a terrific transition to a decompiled function, so I just used that.