我正在使用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'引发了类型异常
  'System.ObjectDisposedException'


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

事实是,该行在应用程序的不同位置重复使用。

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


有时在上下文中,有时在我使用include时,有时在不包括在内时。所以我的问题是:

我该如何进行空检查并考虑到在处理上下文时它应该工作?进行空检查时,我无权访问DbContext

我有3种情况:


record.XmlFormat渴望加载。然后,我要使用热切加载的XmlFormat
record.XmlFormat不是急切加载的,但是上下文是开放的。然后我要延迟加载它。
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.
}

10-08 20:12