Given:
public SomeEntity Read(int primaryKey)
{
SomeEntity myEntity;
using (var context = new MyEntities2())
{
context.Configuration.LazyLoadingEnabled = false;//This line is wacky
myEntity = context.SomeEntities.SingleOrDefault(ct => ct.PrimaryKey == primaryKey);
if (myEntity == null)
return myEntity;
//Force eager Load...
var bypassDeferredExecution = myEntity.RelatedTable1.ToList();
var bypassDeferredExecution2 = myEntity.RelatedTable2.ToList();
}
return myEntity;
}
If I set LazyLoadingEnabled = false then myEntity.RelatedTable1.Count == 0.
Leave at the default LazyLoadingEnabled = true then myEntity.RelatedTable1.Count == 2.
My understanding is that Lazy Loading and Eager Loading are polar opposites. I forced eager loading. I expect my related table (a cross reference table) to have 2 results whether or not I use lazy loading. So in my mind these results make no sense.
Why does lazy loading impact my results?
You have to use Include to eagerly load related entities:
myEntity = context.SomeEntities
.Include("RelatedTable1")
.Include("RelatedTable2")
.SingleOrDefault(ct => ct.PrimaryKey == primaryKey);
Setting Lazy Loading to false won't cause it happen automatically.
If you are using lazy loading, then there needs to be a LINQ to Entities Include method call to identify the (foreign keyed) tables to eagerly load.
Navigation property isn't query, it's enumerable collection. You have 2 ways to get it from DB:
- Lazy loading (will be loaded on the first access to property)
- Eager loading (will be loaded after executing main query if you add Include({propertyName} method
So, if you turned off lazy loading and don't add Include methods to the query each navigation property will be empty (empty collection or null value for single entities)
The following code should work for your case:
myEntity = context.SomeEntities
.Include("RelatedTable1")
.Include("RelatedTable2")
.SingleOrDefault(ct => ct.PrimaryKey == primaryKey);
Lazy loading defers the initialization of an object until it is needed. In this case it will automatically execute a query to the DB to load the object requested.
Eager loading loads a specific set of related objects along with the objects that were explicitly requested in the query.
So in order to use Eager Loading you need to specify the related objects that you want to load.
In EF you can achieve this using the method Include from ObjectQuery.
context.Entity.Include("RelatedObject");
Related
Could Someone help me to clarify the difference between :
var query = awlt.People.Include(p => p.EmailAddresses)
.Where(p => p.LastName.Equals(lastName))
.SelectMany(a => a.EmailAddresses)
.Select(a => a.EmailAddress1);
var query = awlt.People
.Where(p => p.LastName.Equals(lastName))
.SelectMany(a => a.EmailAddresses)
.Select(a => a.EmailAddress1);
I get the same results in both cases without knowing the difference .
Does the Eager Loading require using Include ?
The both query are retrieving the related data just first query by using Eager Loading (and yes Eager loading is achieved by use of the Include method as you guessed) and the second query by using Lazy loading which is by default. But since your query will only returns EmailAddresses because of the Select() and SelectMany() operations the Include() method doesn't change the behavior. To see when Include() method is matter in your example read the following lines that I will prove it in one example:
To know some difference between this two kind of loading related entities Eager loading is typically more efficient when you need the related data for all retrieved rows of the primary table. And also when relations are not too much, eager loading will be good practice to reduce further queries on server. But when you know that you will not need a property instantly then lazy loading maybe a good choice. And also eager loading is a good choice in a situation where your db context would be disposed and lazy loading could not take place anymore.
To prove that one is Lazy Loading and one is Eager Loading consider the following code:
public List<Person> GetEmailAddresses()
{
using (yourEntities awlt = new yourEntities())
{
var query = awlt.People
.Where(p => p.LastName.Equals(lastName));
return query.ToList();
}
}
After calling this method, You cannot load the related entity lazily because the db is disposed. To prove try this:
var query = GetEmailAddresses();
foreach (var item in query.SelectMany(a => a.EmailAddresses).Select(a => a.EmailAddress1))
{
MessageBox.Show(item);
}
And you will get this error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
But if you change the GetEmailAddresses to use Eager Loading like this:
public List<Person> GetEmailAddresses()
{
using (yourEntities awlt = new yourEntities())
{
var query = awlt.People.Include("EmailAddresses")
.Where(p => p.LastName.Equals(lastName));
return query.ToList();
}
}
Then the below code should works fine:
var query = GetEmailAddresses();
foreach (var item in query.SelectMany(a => a.EmailAddresses).Select(a => a.EmailAddress1))
{
MessageBox.Show(item);
}
So in a situation where your db context would be disposed the Eager Loading would be a better choice.
Don't know about EF 7, but in EF 6 both those statements produce the same queries to database and so are essentially the same. There is no lazy loading, no eager loading (in a sense this term is usually used) whatsoever.
You need to Include only properties of entities you materialize. In the example above you materialize Person.EmailAddresses.EmailAddress1, but you include just Person.EmailAddresses - this has no effect (for more details see for example here).
Consider this sample code (details does not matter, there is just Error entity with Code navigation property):
// note we materialized query
var errors = ctx.Errors.Include(c => c.Code).ToArray();
// no lazy loading happens here - we already loaded all related Codes with Include
var codeIds = errors.Select(c => c.Code.CodeID).ToArray();
And this one:
// no need to include here!
var codeIds = ctx.Errors.Select(c =>c.Code.CodeID).ToArray();
And with include:
// include has no effect here!
var codeIds = ctx.Errors.Inlcude(c => c.Code).Select(c => c.Code.CodeID).ToArray();
What is eager loading? It's when you include additional data to the related entity using Include statement. Here Include statement has no effect, it's just does nothing, so we cannot name that eager loading.
What is lazy loading? It's when navigation property is loading when you access it for the first time. You do not do this in your examples, so there is no lazy loading either.
Both examples just execute identical queries to database (after you materialize them with enumeration`ToArray` etc).
The result of the two queries is exactly the same (also about 'eager' and 'lazy' load).
In this case I think that also the query are very similar or the same BUT never trust EF Provider generated queries. To see the generated queries you can stop the program with a breakpoint and have a look to query object (pointing the mouse on it). That is the query generated by EF Provider.
About Eager loading (the Include statement) in this case it should not be useful because is used to load properties of the output object. In this case you are selecting EMailAddress1 so with Include you could eager load properties of EMailAddress1 (and avoid lazy queries during EMailAddress1 access).
You can find the difference if you look into SQL Server Profiler after the query is run. So in your first case there is only one query going to your database and fetching records from People table as well as EmailAddresses table whereas in the second case it does two queries to database and fetches People first and then EmailAddresses in a second query. Thus the first scenario is called eager loading and the second one lazy loading.
I am having a very peculiar problem: the ToList() extension method is failing to convert results to a list. here is my code, standard boilerplate linq query, I converted ToList() twice for good measure
var assets = new List<Asset>();
using (var ctx = new LeaseContext())
{
assets = ctx.Assets.OrderBy(o => o.Reference).Where(w => w.Status == AssetStatus.Active).ToList();
assets.ToList();
}
return assets;
yet the assets are still a list of System.Data.Entities.DynamicProxies....
I've never had this problem before.
The reason is lazy loading. When lazy loading is enabled in EF (by default), then (again, by default) EF creates dynamic proxies for each entity. It's required for loading related entities. Dynamic proxy will be inherited from entity class. So in your case it will be inherited from Asset. But dynamic proxy will have reference to the context which created its instance. And it will override navigation properties (which are virtual) to query entities via context which is stored in dynamic proxy.
And it's completely legal to add instances of derived types to list of base type.
If you don't want dynamic proxies, then just disable lazy loading and proxy creation:
ctx.Configuration.LazyLoadingEnabled = false; // turn-off loading on-demand
ctx.Configuration.ProxyCreationEnabled = false; // turn-off wrapper class generation
Technically you can just turn-off proxy generation and lazy loading will not work. But I prefer to turn-off both settings explicitly.
I have an EF model where I have set lazy loading to true. I do this query:
public static WorkflowStatus Get(int id)
{
WorkflowStatus status;
using (var db = new WorkflowDb())
{
status = db.WorkflowStatuses
.Include("CurrentMappings")
.Include("CurrentMappings.NextWorkflowStatus")
.Include("NextMappings")
.Include("NextMappings.CurrentWorkflowStatus")
.Include("WorkQueueWorkflowStatusMaps")
.Include("WorkQueueWorkflowStatusMaps.WorkQueue")
.FirstOrDefault(x => x.Id == id);
}
return status;
}
After I get the status back there is more than just those things being populated. For example each WorkQueueWorkflowStatusMap has a WorkQueue and WorkQueue has a collection of WorkQueueWorkflowStatusMaps - so there is an infinite amount of back and forth being loaded. How do I get that to stop? When I return this through a WCF service in another layer it throws an exception because of this.
How to stop EF from loading entire object graph?
By all those includes you told EF to load whole object graph. Every include says: load this relation as well.
so there is an infinite amount of back and forth being loaded
No. Entities are loaded only once. What you see is circular reference which is included in your model. If your WorkQueueWorkflowStatusMap has WorkQueue navigation property and in the same time WorkQueue has WorkQueueWorkflowStatusMap navigation property than you modeled circular reference which is absolutely correct until you try to serialize your entity = problem in WCF. In such case you must inform serializer that circular references are used.
If you want to use serialization and WCF you should follow #Eranga's deleted answer - turn off lazy loading and proxy creation.
From Getting Started with Entity Framework 4 – Lazy Loading:
context.ContextOptions.LazyLoadingEnabled = true;
Stop deep loading by add .AsNoTracking()
db.WorkflowStatuses.Include(s => s.childObject)
.AsNoTracking()
In Entity Framework 4, what is the difference between Lazy Loading, and using Load() method?
Edit: I have added, two 'if' statements:
Lazy Loading:
var query = from c in context.Contacts select c;
foreach ( var contact in query ) {
if ( contact.ID == 5 )
Console.WriteLine( contact.Addresses.City );
}
Load() method:
context.ContextOptions.LazyLoadingEnabled = false;
var query = from c in context.Contacts select c;
foreach ( var contact in query ) {
if ( contact.ID == 5 ) {
contact.Addresses.Load()
Console.WriteLine( contact.Addresses.City );
}
}
Now, having this two 'if' checks, why should I preffer one before another?
Lazy Loading means that a load will only occur once the object is needed, thus not loading unnecessary data.
When you disable Lazy Loading you say that you will load yourself by calling load.
http://en.wikipedia.org/wiki/Lazy_loading
Lazy Loading is disabled by default, so when you set it to false in your first line it does not do anything.
When you call Load, you will load all the related objects to that database (which is not needed in this case which makes it work without it)
This post on Working with Lazy Loading in EF 4 Code First should also help with understanding how Entity Framework behaves both with and without lazy loading enabled. It also demonstrates that it is enabled by default in EF4 and how to disable it on a per-instance or by default for your application basis.
I have my NHibernate mappings set to lazy loading = true.
In my CustomersViewModel I have something like:
foreach (Customer c in _customerRepository)
{
this.Customers.Add(new SingleCustomerViewModel(c));
}
This obviously kills all the lazy loading, since the customers are passed one by one.
How do I get my collections (including subcollections and sub-subcollections a.s.f.) of model-objects into the corresponding ObservableCollections of my ViewModels to bind to the UI?
This seems to be a common problem, but I found no answer, neither here nor on the Googles ...
I am not sure I completely understand the question .
But I was thinking why not change your getCustomers method to
IEnumerable<SingleCustomerViewModel> getCustomers(){
return from c in _customerRepository select SingleCustomerViewModel(c);
}
Since LINQ expressions are lazily evaluated you nhibernate collection wont be initialized until its actually bound to the UI .
This is a classic "SELECT N+1" problem: whichever query layer you are using for NHibernate offers you a way to eagerly load the child collections in your initial query to avoid this row-by-row query pattern.
With the LINQ provider, for example:
session.Query<Customer> ()
.FetchMany (c => c.Widgets) // eagerly load child collections
.ThenFetchMany (w => w.Frobbers); // now get grandchild collection
If you're using HQL, just add the fetch keyword to your joins.