在 LinqToSql 中,预编译查询很棒——但它仍然需要我在第一次使用查询时对编译性能造成影响。
我想在应用程序启动时在后台“预热”这些预编译查询。显然,我可以通过使用一些默认参数调用它们来做到这一点 - 但是这会对数据库造成不必要的打击。
有没有办法在不调用数据库的情况下“预热”预编译的查询?
我查看了 CompliedQuery 源代码,但似乎需要的许多类都是密封的和/或内部的......
在 LinqToSql 中,预编译查询很棒——但它仍然需要我在第一次使用查询时对编译性能造成影响。
我想在应用程序启动时在后台“预热”这些预编译查询。显然,我可以通过使用一些默认参数调用它们来做到这一点 - 但是这会对数据库造成不必要的打击。
有没有办法在不调用数据库的情况下“预热”预编译的查询?
我查看了 CompliedQuery 源代码,但似乎需要的许多类都是密封的和/或内部的......
好的,所以查看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);
}