We use Entity Framework 4.2 with the first approach of model and code generation DbContext.
Let's say we have the following data model within an entity:
class Person { public string Name { get; set; } public Address Address { get; set; } } class Address { public string City; { get; set; } }
The scenario is as follows:
- ViewModel wants to load some data from a database
- To load data, a task is created (asynchronous operation). This is because we do not want the user interface to freeze when loading data.
- A task (which runs in a separate thread) creates a new database context and loads data (for example, a Person object) from the database
- Completed task completion and database context.
- The main topic is notified of the completion of the task. The main theme is now accessing the loaded Person object.
- The view tries to show the name and address of the person in the text field through data binding.
- The view refers to Person.Name (no problem here)
- The view opens Person.Address.City → OOPS! The database context has already been deleted (since the download was in a separate thread) and due to lazy loading Person.Address is not available!
In phase 3, the user is logged in as follows:
using (DatabaseContext context = new DatabaseContext()) { Person person = from p in context.Persons.FirstOrDefault(); return person; }
Well, I know that (theoretically) I could force load the Address object in two ways: 1) Use DbSet.Include, for example:
context.Persons.Include("Address").FirstOrDefault();
2) Access Person.Address when the database context is still alive, as this will cause the address to load
Person person = context.Persons.FirstOrDefault(); Address address = person.Address; return person;
Of course, the first one is the preferred solution, because it is not as ugly as the second (just accessing the property to force the data to be downloaded, and then discarding the IS result is ugly). In addition, if I collected (for example, a list of persons), I would have to scroll through the collection and access the Address separately for each person. The problem with the first solution is that only DbSet has the Include method, and all other collections returned from the queries do not. So let's say I have a database structure
class Resource {} class Person : Resource { public Address Address { get; set; } } class Appointment { public IList<Resource> Resources { get; set; } }
and I want to download all the specific meetings and include the address in every resource that is a person, I have problems (or at least I could not understand how to write a request for him). This is because context.Appointments.Resources is not of type DbSet, but of ICollection, which does not have an Include method. (Well, maybe in this case I could write the query somehow, starting with context. Persons instead of context. Items so that I can use Include, but there are many scenarios where this is not possible)
So basically questions :
- Is this the right way to access asynchronous databases first?
- How to solve problems with lazy loading? Turning lazy loading is not a solution (unless it can only be done for certain objects?)