如何“预热”LinqToSql预编译查询?

时间:2014-06-20 18:21:17

标签: c# linq-to-sql compiled-query

在LinqToSql中,预编译的查询很棒 - 但它仍然需要我在第一次使用查询时获取编译性能。

我希望在应用程序启动时在后台“预热”这些预编译的查询。显然,我可以通过使用一些默认参数调用它们来做到这一点 - 但是这会导致对数据库的不必要的打击。

有没有办法在没有调用数据库的情况下“预热”预编译查询?

我已经看过CompliedQuery源代码,但似乎所需的许多类都是密封的和/或内部的......

1 个答案:

答案 0 :(得分:0)

好的,所以查看从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;
    }

因此没有办法强制编译而不实际执行它。

然而,我确实找到了一个hacky解决方法,它给了我我需要的东西。有一种方法可以执行查询,从而导致查询被预编译而不允许调用数据库:

// 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);
}