c# - 在空检查中获取 ObjectDisposedException

标签 c# entity-framework

我正在使用 Entity Framework 6.x,一个实体看起来像这样(有些简化):

public partial class Record
{
    public int Id { get; set; }
    public string Name { get; set; }

    public Nullable<int> XmlFormatID { get; set; }
    public virtual XmlFormat XmlFormat { get; set; }
}

我是这样使用它的,但在实际代码中它使用不同的方法:

Record record = null;
using(var context = new DbContext())
{
    record = context.Records.FirstOrDefault(x => x.Id == id);
}

// Now the context is (correctly) disposed.
if (record.XmlFormatID.HasValue && record.XmlFormat != null)
{
    // It crashes before in this if.
}

上面的代码产生了这个异常:

record.XmlFormat = 'record.XmlFormat' threw an exception of type 'System.ObjectDisposedException'

我知道这个错误是因为我在处理上下文时尝试延迟加载实体。我也知道我可以简单地将代码更改为 context.Records.Include(x => x.XmlFormat),或者在上下文打开时执行 if-case。

问题是这条线在应用程序的不同地方被重复使用。

if (record.XmlFormatID.HasValue && record.XmlFormat != null)
{
    // It crashes in this if.
}

有时在上下文中,有时当我使用包含时,有时当它不包含时。所以我的问题是:

我如何进行 null 检查并考虑到它应该在处理上下文时起作用?没有访问 DbContext 当我进行 null 检查时。

我有 3 种情况:

  1. record.XmlFormat 是预先加载的。然后我想使用预先加载的 XmlFormat
  2. record.XmlFormat 不是预先加载的,但上下文是开放的。然后我想延迟加载它。
  3. record.XmlFormat 未预先加载,上下文已释放。然后我根本不想输入 if 并将 XmlFormat 视为 null

最佳答案

据我所知,你做不到。但您可以尝试以下三个选项:

第一个选项。

作为一种解决方法,我建议您关闭LazyLoading 并在需要时使用EagerLoading 获取数据(如您所知) .您可以在上下文的构造函数中全局执行此操作:

public MyContext : base("Name=MyContext")
{
    // Turn off lazy loading and proxy creation
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;
}

或者,如果您想在应用程序的其他部分使用延迟加载,您可以在加载时执行 Record:

Record record = null;
using(var context = new DbContext())
{
    // Turn of lazy loading and proxy creation. 
    // Disabling one of these also should be enough.
    this.Configuration.LazyLoadingEnabled = false;
    this.Configuration.ProxyCreationEnabled = false;

    // Load record
    record = context.Records.FirstOrDefault(x => x.Id == id);
}

// Check for null
if (record.XmlFormatID.HasValue && record.XmlFormat != null)
{
}

如果你不想重复编写延迟加载禁用代码,你可以添加处理它的构造函数:

public MyContext(bool enableLazyLoading) 
    : this()
{
    this.Configuration.LazyLoadingEnabled = enableLazyLoading;
    this.Configuration.ProxyCreationEnabled = enableLazyLoading;
}

然后将其用作:

using(var context = new DbContext(false))
{
    record = context.Records.FirstOrDefault(x => x.Id == id);
}

第二个选项。

如果您可以访问上下文,则可以通过检查 Database.Connection 来检查它是否已被释放。将此方法添加到您的上下文中:

public bool IsDisposed()
{
    bool isDisposed = false;
    try
    {
        isDisposed = Database.Connection != null;
    }
    catch (InvalidOperationException ex)
    {
        isDisposed = true;
    }
    return isDisposed;
}

然后将检查添加到您的 if 条件:

Record record = null;
Context context = null; 
using(context = new DbContext())
{
    record = context.Records.FirstOrDefault(x => x.Id == id);
}

// Check
if (context != null
        && !context.IsDisposed()
        && record.XmlFormatID.HasValue 
        && record.XmlFormat != null)
{
}

第三个选项

最后但同样重要的是,您始终可以处理 ObjectDisposedException。将此方法添加到您的 Record 模型中:

class Record
{
    ...

    public bool IsXmlRootLoaded
    {
        bool isLoaded = false;
        try
        {
            isLoaded = XmlFormatID.HasValue && XmlFormat != null;
        }
        catch(ObjectDisposedException ex)
        {
            isLoaded = false;
        }
        return isLoaded;
    }
}

然后检查是否加载了XmlFormat:

if(record.IsXmlRootLoaded())
{
    // Do what you want.
}

关于c# - 在空检查中获取 ObjectDisposedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39159077/

相关文章:

c# - 子类中的父元素

c# - 位图和位图数据的区别

entity-framework - ef core 2.0scaffold-dbcontext自定义命名空间

c# - 我的项目中安装了哪个版本的 Entity Framework ?

c# - Entity Framework 。包括创建不正确的 JOIN?

c# - 我应该将一个可空的 double 类型转换为一个整数吗?

c# - 从字符串中获取 HTML 标签

c# - 使用 Irony 解析时包含空格

c# - 提交后如何在后面的代码中重置RadAsyncUpload?

c# - 为什么我的 Entity Framework 代码不首先 DbContext 显示我填充的表中的实体?