配置 EF 在访问导航属性未急切加载(且延迟加载已禁用)时抛出异常

Jam*_*ing 6 entity-framework lazy-loading eager-loading entity-framework-4

我们有一些应用程序当前正在使用启用了延迟加载的 EF 模型。当我关闭延迟加载(以避免隐式加载和我们的大多数 N+1 选择)时,我宁愿访问应该已经热切加载(或在引用上手动 Load() )抛出异常而不是返回 null(因为特定的异常比 null 引用更好、更容易调试)。

我目前倾向于仅修改 t4 模板来执行此操作(因此,如果 reference.IsLoaded == false,则抛出),但想知道这是否已经是一个已解决的问题,无论是在框中还是通过另一个项目。

任何对可以进行源分析并检测此类问题的插件/扩展/等的引用的奖励积分。:)

Jar*_*ore 3

出于几个与性能相关的原因,我想做同样的事情(引发延迟加载) - 我想避免同步查询,因为它们会阻塞线程,并且在某些地方我想避免加载完整的实体,而只是加载属性代码需要的。

仅禁用延迟加载还不够好,因为某些实体具有可以合法为 null 的属性,并且我不想将“null 因为它是 null”与“null 因为我们决定不加载它”混淆。

我还只想选择性地在某些特定的代码路径中启用延迟加载,我知道延迟加载是有问题的。

以下是我的解决方案。

在我的 DbContext 类中,添加此属性:

class AnimalContext : DbContext
{
   public bool ThrowOnSyncQuery { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在我的代码启动的某个位置,运行以下命令:

// Optionally don't let EF execute sync queries
DbInterception.Add(new ThrowOnSyncQueryInterceptor());
Run Code Online (Sandbox Code Playgroud)

其代码ThrowOnSyncQueryInterceptor如下:

public class ThrowOnSyncQueryInterceptor : IDbCommandInterceptor
{
    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        OptionallyThrowOnSyncQuery(interceptionContext);
    }

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        OptionallyThrowOnSyncQuery(interceptionContext);
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
    }

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        OptionallyThrowOnSyncQuery(interceptionContext);
    }

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }

    private void OptionallyThrowOnSyncQuery<T>(DbCommandInterceptionContext<T> interceptionContext)
    {
        // Short-cut return on async queries.
        if (interceptionContext.IsAsync)
        {
            return;
        }

        // Throw if ThrowOnSyncQuery is enabled
        AnimalContext context = interceptionContext.DbContexts.OfType<AnimalContext>().SingleOrDefault();
        if (context != null && context.ThrowOnSyncQuery)
        {
            throw new InvalidOperationException("Sync query is disallowed in this context.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在使用的代码中AnimalContext

using (AnimalContext context = new AnimalContext(_connectionString))
{
    // Disable lazy loading and sync queries in this code path
    context.ThrowOnSyncQuery = true;

    // Async queries still work fine
    var dogs = await context.Dogs.Where(d => d.Breed == "Corgi").ToListAsync();

    // ... blah blah business logic ...
}
Run Code Online (Sandbox Code Playgroud)

  • 我不明白这如何有助于检测延迟加载和引发异常。这不是只是检测同步查询吗? (2认同)