Как я могу "разогреть" предварительно скомпилированный запрос LinqToSql?

В LinqToSql предварительно скомпилированные запросы - это хорошо, но мне все равно нужно, чтобы я испытал производительность компиляции при первом использовании запроса.

Я хотел бы "разогреть" эти предварительно скомпилированные запросы в фоновом режиме при запуске приложения. Очевидно, что я могу сделать это, вызывая их с некоторыми параметрами по умолчанию - однако это приводит к ненужному попаданию в базу данных.

Есть ли способ "разогреть" предварительно скомпилированный запрос, не обращаясь к базе данных?

Я взглянул на исходный код CompliedQuery, но кажется, что многие из необходимых классов запечатаны и / или внутренние...

1 ответ

Решение

Итак, глядя на исходный код для CompiledQuery который возвращается из CompiledQuery.Compile() мы можем убедиться, что запрос фактически скомпилирован только после первого вызова метода:

    ICompiledQuery compiled; 
    private object ExecuteQuery(DataContext context, object[] args) {
        if (context == null) { 
            throw Error.ArgumentNull("context");
        } 
        if (this.compiled == null) { 
            lock (this) {
                if (this.compiled == null) { 
                    // This is where the query is copmiled
                    this.compiled = context.Provider.Compile(this.query);
                    this.mappingSource = context.Mapping.MappingSource;
                }
            } 
        }
        // this is where the query is executed against the data store
        return this.compiled.Execute(context.Provider, args).ReturnValue;
    }

Таким образом, нет способа форсировать компиляцию без ее фактического выполнения.

Тем не менее, я нашел хакерский обходной путь, который дает мне то, что мне нужно. Есть способ, которым мы можем выполнить запрос, таким образом вызывая его предварительную компиляцию, не допуская обращения к базе данных:

// compiled query
static Func<NorthwindDataContext, int, IQueryable<Order>> GetOrderById =
    CompiledQuery.Compile((NorthwindDataContext db, int orderId) => LINQ GOES HERE );


static void Warmup() 
{
    var context = new NorthwindDataContext("ConnectionString");
    // dispose the connection to force the attempted database call to fail
    context.Connecction.Dispose(); 
    try  
    {
         GetOrderById(context, 1);
    }
    catch (Exception ex)
    {
         // we expect to find InvalidOperationException with the message
         // "The ConnectionString property has not been initialized."
         // but the underlying query will now be compiled
    }
}

static void GetData() 
{
     // as long as we called warmup first, this will not take the compilation performance hit
     var context = new NorthwindDataContext("ConnectionString");
     var result = GetOrderById(context, 1);
}
Другие вопросы по тегам