Interesujące pytanie. Biorąc go do dekompilowana źródeł, podczas kompilowania kwerendy, to co się dzieje:
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>);
}
Sposób UseExpressionCompile jest zdefiniowany następująco:
private static bool UseExpressionCompile(LambdaExpression query)
{
return typeof (ITable).IsAssignableFrom(query.Body.Type);
}
Ta wartość false dla wyrażenia zdefiniowaniu , więc używany jest inny przypadek.
Invoke jest tak:
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 jest jak:
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;
}
W tym przypadku nasz dostawca klasa SqlProvider The SqlProvider.CompiledQuery jest klasa, która implementuje ICompiledQuery.Wykonać na tej klasy jest realizowany:
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 wzywa SqlProvider.Execute, który jest dość duży sposób, więc będę zamieszczać Highlights:
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);
}
}
W między pozyskiwania i zwalniania połączenie to wygasza polecenia sql. Więc powiedziałbym, że masz rację. Wbrew powszechnemu przekonaniu, skompilowane zapytania nie zachowują się tak samo jak nieskompilowane zapytania, jeśli chodzi o odroczone wykonanie.
Jestem prawie pewny, że możesz pobrać aktualny kod źródłowy ze stwardnienia rozsianego, ale nie mam tego pod ręką, a Resharper 6 ma niesamowite przejście do funkcji dekompilowanej, więc właśnie to wykorzystałem.
Masz rację. Skompilowane zapytania nie są kompozycyjne, zwracają wyniki, gdy delegate jest wywoływane, a nie samo zapytanie. Zmieniłem swoją odpowiedź na zadane pytanie. – alex