1

在 LinqToSql 中,预编译查询很棒——但它仍然需要我在第一次使用查询时对编译性能造成影响。

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

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

我查看了 CompliedQuery 源代码,但似乎需要的许多类都是密封的和/或内部的......

4

1 回答 1

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);
}
于 2014-06-21T17:57:13.883 回答