I'm using Entity Framework 6.x and one entity looks like this (somewhat simplified):
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; }
}
And I use it like this, but in actual code it's in different methods:
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.
}
The code above generates this exception:
record.XmlFormat = 'record.XmlFormat' threw an exception of type 'System.ObjectDisposedException'
I do know that the error is caused because I try to lazy-load an entity when the context is disposed. I also know that I can simply change the code to context.Records.Include(x => x.XmlFormat), or do the if-case when the context is opened.
The thing is that this line is re-used on different places in the application.
if (record.XmlFormatID.HasValue && record.XmlFormat != null)
{
// It crashes in this if.
}
Sometimes within the context, sometimes when I've used include, and sometimes when it's not included. So my question is:
How can I do the null-check and also take into account that it should work when the context is disposed? I do not have access to DbContext when I do the null-check.
I have 3 scenarios:
record.XmlFormat is eager-loaded. Then I want to use the eager-loaded XmlFormat.record.XmlFormat is not eager-loaded, but the context is open. Then I want to lazy-load it.record.XmlFormat is not eager-loaded and the context is disposed. Then I simply don't want to enter the if and treat XmlFormat as null.As far as I know, you cannot do it. But you can try three options below:
As a workaround, I suggest you to turn off LazyLoading and get data using EagerLoading when you need it (as you already know). You can do it globally in the constructor of your context:
public MyContext : base("Name=MyContext")
{
// Turn off lazy loading and proxy creation
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
Or, if you want to use lazy loading at another parts of your application, you can do it while loading 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)
{
}
If you do not want to write lazy loading disabling code repeatedly, you can add constructor which handles it:
public MyContext(bool enableLazyLoading)
: this()
{
this.Configuration.LazyLoadingEnabled = enableLazyLoading;
this.Configuration.ProxyCreationEnabled = enableLazyLoading;
}
Then use it as:
using(var context = new DbContext(false))
{
record = context.Records.FirstOrDefault(x => x.Id == id);
}
If you can have access to context, you can check if it has been disposed or not, by checking Database.Connection. Add this method to your context:
public bool IsDisposed()
{
bool isDisposed = false;
try
{
isDisposed = Database.Connection != null;
}
catch (InvalidOperationException ex)
{
isDisposed = true;
}
return isDisposed;
}
Then add checks to your if condition:
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)
{
}
Last, but not least, you can always handle ObjectDisposedException. Add this method into your Record model:
class Record
{
...
public bool IsXmlRootLoaded
{
bool isLoaded = false;
try
{
isLoaded = XmlFormatID.HasValue && XmlFormat != null;
}
catch(ObjectDisposedException ex)
{
isLoaded = false;
}
return isLoaded;
}
}
Then check if XmlFormat has been loaded:
if(record.IsXmlRootLoaded())
{
// Do what you want.
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With