When requiring to eager load certain relations, I have noticed that in EF Core (v. 1.1.0) calling the Include method alone will not attach the required relation to the query, and when dealing with situation such as when the query must be passed to a view (ASP.Net MVC Core) where lazy loading will not work this causes problems.
However, I know that calling the Load method after the Include solves this problem. On the other hand, I also know that the Load is very similar to ToList as all the data available in a table will be loaded into the memory.
The point is that, I have faced situations where I have to call Load in order to be able to make a query based on properties available in a relation and I believe that this is a bad idea and using a Join would be more appropriate.
There are two questions:
1- Is calling Load really a bad idea in comparison with using a Join in order to attach navigational or relational properties?
2- What is the point of Include then if it does not include things on its own?
Related
I have a Grid control (WinForms) that is used for viewing/updating data but executing SaveChangesAsync() is very slow (3 seconds) for updating one object. I'm finding it difficult to solve this performance issue while also sticking with DDD.
One might suggest using a CRUD approach instead of DDD, but this is only a part of the application. Would I want to use CRUD for this view, if I use DDD in other parts of the app? Seems like it would break encapsulation and confuse other developers on the project. If I did this, would I put them in separate bounded contexts?
Another option is to enable AsNoTracking*(). The problem is that my aggregate is Product and the entity is ProductRecipe (the parts needed to make the product). I only need to track ProductRecipe entities, but since ProductRecipes are accessed via the aggregate Product, I need to track them the same.
My final option is to just make ProductRecipe an aggregate which would allow me to query it separately from Product.
What's the best way to fix this performance issue?
Details:
EF Core 5
WinForms
I have an issue, which I assume many professional developers will run into. My workplace has adopted entity framework. We use it, and love it. However, we seem to have run into a very frustrating limitation.
Let's assume you have an object chain as such
A -> B -> C -> D
We are professionals, so these objects have a lot of data, and there is a lot of them in their respective database tables. It seems EF has a terrible time loading anything past object B. The SQL queries it generates are really inefficient and not good. The call would be something like
context.objects.include("bObjectName.cObjectName.dObjectName").FirstOrDefault(x => x.PK == somePK);
We have gotten around this by explicitly loading objects past that second level with the .Load() command. This works well for single objects. However, when we talk about a collection of objects, we start to run into issues with .Load().
Firstly, there does not seems to be a way to keep proxy tracking of objects in a collection without the virtual keyword. This makes sense because it needs to overwrite the get and set functions. However, this enables lazy loading, and .Load() doesn't map entities when lazy loading is enabled. I find this to be somewhat odd myself. If you remove the virtual keyword, .Load() does automatically link loaded objects to the relevant objects in context.
So here is the crux of my issue. I want proxy tracking, but also want .Load() to map the navigation properties for me. None of this would be an issue if EF could generate good queries. I understand why it can't, it has to be a one show fits all kind of thing.
So to load the third tier of objects I might create a loader function in my service layer that takes all the primary keys of the second tier of objects, and then calls a .Load() on them.
Does anyone have a solution for this? It seems like EF7, or Core 1.0 solves this by:
Removing lazy loading entirely, which we could shut off as well, but it would break a lot of older code.
Adding a new "ThenInclude" feature, which supposedly increases the efficiency of chaining includes massively.
If turning off lazy loading is the answer, that's fine, I just want to exhaust all options before I waste a lot of time redeveloping a huge webapps worth of service calls.
Does anyone have any ideas? I'm willing to give anything a shot. We are using EF6.
EDIT: It seems the answer is to shut off lazy loading at a context level, or upgrade to EF7. I'll change this if anyone else manages to find a solution whereby you can have proxy tracking with forced eager loading on a single object for EF6.
You're absolutely right about chained .Include() statements, the performance documentation warns against chaining more than 3 as each .Include() adds an outer join or union. I didn't know about ThenInclude but it sounds like a gamechanger!
If you keep your virtual navigation properties but turn off Lazy Loading on the DbContext
context.ObjectContext().ContextOptions.LazyLoadingEnabled = false;
then (as long as Change Tracking is enabled) you can do the following:
var a = context.aObjectNames.First(x=> x.id == whatever);
context.bObjectNames.Where(x=> x.aId == a.Id).Load()
This should populate a.bObjects
My project uses Entity Framework 6 with Repository & UnitOfWork patterns to communicate with a MSSQL database. all configurations are done with Code First.
All of the navigation properties of the Entity Objects are defined for lazy loading as such:
public virtual ICollection<> Items { get; set; }
this works well, and the performance is pretty good in most cases. in some cases, however, where the navigation properties refer to a large sets of data, loading them to memory takes a while, at which point LINQing seem like a bad practice. to improve performance, it would make sense to convert some of them to IQueryable<> but EF doesn't seem to accept that kind of configuration.
So although i could workaround this by "Querying" the repositories, in some cases i already have an entity object in memory and it feels right to be able to query its navigation properties without loading all of them, to get the data that i need via LINQ.
Is there a way to make this work?
You do not. This functionality is not available in Entity Framework. YOu can make a feature request. But right now - no way.
With EF 4.1, you used to remove the IncludeMetadataConvention in order to prevent EF from querying for database metadata on every query.
In EF 5, I get a warning about IncludeMetadataConvention being obsolete, and in LinqPad, I can see that EF is now querying for migration history on every use. I'm working on a database first project (but using POCO's and DbContext). I don't want the overhead of these extra queries. How do I turn them off?
Update
I found that I can disable this on a per-dbContext basis by calling
System.Data.Entity.Database.SetInitializer<theDbContext>(null);
However, I would like to be able to disable initialization globally (Imagine a large app, and we want to ensure that we are not running these queries (and definitely not trying to create a database) when it is deployed for production.
If you need to do it for every context type in your large application you can create some code which will go through all of your assemblies, find all types derived from DbContext and invoke that call through reflection for every found type.
Btw. since EF 4.3 you can also change initializer from configuration but it is still per context basis because people usually don't have more than one.
Why not put the code in the constructor of your DbContext classes?
I do this as well as set a parameter to disable AutoDetectChangesEnabled, LazyLoading & Proxy CreationEnabled.
Is there a way to get entity objects to automatically pull all relevant data through the relationships instead of having having to .Include everything I want populated? I can't use lazy loading as this needs to be serialized to go over WCF. It would just be fantastic to have it auto populate the relevant collections.
No there is no build in feature which will automatically eagear load whole object graph. You must always explicitly say which navigation properties you want to eager load (by using Include method or LoadProperty method).
Edit:
Based on your comment: Generally it should be possible to build some auto loader - but it will not be easy. ObjectContext has MetadataWorkspace property which contains all metadata about your entities. You can load all information about your entities from metadata and add needed inclueds to the query. I expect one problem - you must somehow handle cyclic references. If you need some example how to extract information about entities check T4 POCO generation template.
I came across this querstion recently because I was looking for something similar.
Since EF Core 6 there is a AutoInclude method that configures whether a navigation should be included automatically.
This can be done in the OnModelCreation method in the DbContext class:
modelBuilder.Entity<Theme>().Navigation(e => e.ColorScheme).AutoInclude();
This would load the ColorScheme for every Theme when running the query:
var themes = context.Themes.ToList();
See Model configuration for auto-including navigations