简体   繁体   中英

Entity framework DbContext and lazy loading

I'd like to use lazy loading in my application using entity framework, to get data from the database. I read here among the answers about the DbContext that:

The context should be created per request.

If I use this way, then the following exception raises:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

And of course this is because I dropped the context after executing the query. Here I read that, I can explicitly load the data, but I don't want to load the data from other tables.

So what do you suggest, how should I use the DbContext to be able to properly use lazy loading?

Your expectation and your current execution are contradicting one another.

I'd like to use lazy loading in my application

The ObjectContext instance has been disposed and can no longer be used

The error message clearly reveals that you are still expecting to access data (via lazy loading) after you've closed your context, which is impossible.

There are two solutions here:

1. Ensure you don't close your context until you're done lazily loading data.

This is how you're suppose to do lazy loading, by design. Assuming you're using a using statement, ensure that you only fetch data while inside the using block.

However, you will notice that in large codebases, it becomes hard to ensure that the context is kept open long enough. Which I why I urge you to consider the other option:

2. Switch to eager loading.

Lazy loading is a very simple approach and works well enough in tiny applications (eg when I write a short-term-usage tool to help me). However, for larger infrastructures, lazy loading starts leading to mistakes that are easy to make but painfully hard to debug.

While eager loading doesn't avoid these runtime exceptions, the exceptions you will encounter (having forgotten an Include statement) will be much easier to debug, compared to having to figure out which data was being lazily loaded at what point.

I'm not going to tell you you can't use lazy loading, but you do need to be aware of the complexities that this leads to. For sufficiently large codebases, it becomes nigh unmaintainable to keep track of whether you closed the context too soon or not.

The cost of maintaining this (and debugging all the issues that you didn't prevent) is going to vastly outweigh the slightly more verbose code required for eager loading.

Alternative to lazy loading - use DbContext instance per query.
Load only data required for current action, especially in web application, where application works in small chunks "request-response".

DbContext is just an object, it's creation is chip.

Lazy loading will quickly introduce issues for example "N + 1" queries.

With instance per query, you will be able to fully benefit of asynchronous queries, where you can executes multiple queries almost simultaneously.

var orderTask = ordersRepository.Find(orderId);  // Takes 1 second
var invoicesTask = invoiceRepository.FindBy(orderId); // Takes 2 seconds
var deliveriesTask = deliveryRepository.FindBy(orderId); // Takes 3 seconds

await Task.WhenAll(orderTask, invoicesTask, deliveriesTask); 

var order = await orderTask;
var invoices = await invoicesTask;
var deliveries = await deliveriesTask;

Three queries will be finished in 3 seconds, instead of 6, if the would be executed one by one.
Single DbContext do not support simultaneous asynchronous calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM