My context is marked with
this.Configuration.LazyLoadingEnabled = false;
I want to load selected related entities. Example like
context.Entry(catalog)
.Collection(p => p.Products)
.Query()
.Where(p => p.VendorId == 1)
.Load();
This works fine.
context.Entry(catalog)
.Collection(p => p.Tags)
.Query()
.Where(p => p.TagId== 1)
.Load();
This works fine too. But I assume this causes two separate Db calls. I want to make this in one call. How can I do that ? (I do not want to use .Include because it loads a huge list of another property values into the category object). Any ideas ?
Update
I want to load both Product and Tag at the same time without loading them separately as above.
Related
I don't know if it is expected to be this way but I thought it is strange since changes the query results.
When I execute the query below I get my entity with only 2 "Mensagens" entity because i'm filtering only the actives so it's right, I have 2 active entities on my database and 1 inactive.
return await context.Lancamentos
.Include(x => x.UsuarioCriacao)
.Include(x => x.Mensagens.Where(m => m.Ativo))
.ThenInclude(m => m.MensagemMedias)
.ThenInclude(m => m.MediaWhatsapp)
.ThenInclude(m => m.TipoMediaWhatsapp)
.Include(x => x.Mensagens.Where(m => m.Ativo))
.ThenInclude(x => x.TemplateMensagem)
.ThenInclude(t => t.Medias)
.ThenInclude(m => m.MediaWhatsapp)
.ThenInclude(m => m.TipoMediaWhatsapp)
.AsNoTracking()
.FirstOrDefaultAsync(l => l.Id == id && l.Ativo);
But if I execute the exact same command just removing the AsNoTracking() line it gives me the 3 records, both active and inactive.
But the inactive one EF doesn't fetch the ThenInclude below. It changes the behaviour.
With AsNoTracking it filters the data according to the filter I used on Include
Without AsNoTracking it bring me all the data but it filters if it will load or not the ThenInclude objects.
Does anyone know if this is a normal behaviour and why does it behaves like this?
This is sort of explained in Filtered include documentation:
Caution
In case of tracking queries, results of Filtered Include may be unexpected due to navigation fixup. All relevant entities that have been queried for previously and have been stored in the Change Tracker will be present in the results of Filtered Include query, even if they don't meet the requirements of the filter. Consider using NoTracking queries or re-create the DbContext when using Filtered Include in those situations.
So most likely your context is not clean when doing tracking tests. And even if it is clean, in case it is used for executing other queries, the navigation fixup can load some non satisfying filter entities later since it keeps track (has access) to all tracked entities.
In general you cannot rely on content of navigation property of a tracked entity since it may be updated at any time during the lifetime of the context until the context is disposed or entity detached from change tracker. If you need full control, the either use no tracking entity queries or DTO/ViewModel etc. projecting queries and select exactly what you want (no Include / ThenInclude, just plain LINQ).
return _companyRepository.GetAll().Where(company => company.Id == Id)
.Include(company => company.offices.Where(o => o.IsActive))
.ThenInclude(office => office.People.Where(p => p.IsFired))
.ThenInclude(person => person.Children)
.ToList();
How can I get all fired people of all active offices using Entity Framework Core?
I'm getting this error:
Where clause in not valid inside ThenInclude or Include
company.offices.Where(o => o.IsActive)
office.People.Where(p => p.IsFired)
I know I can not use Where inside Include. the question is how to filter data with Include clause?
It's not possible.
I'd suggest to look around for any of the 3rd party libraries listed there, example :
EntityFramework.Filters
Query IncludeFilter
How to filter “Include” entities in entity framework?
You do not need to use any Include, in case of you use your data in your query. Include is just a way to disable Lazy Loading. Include controls whether a navigation property is filled with data or not. Include is not made to filter anything.
Your query will also return companies (with people) not people.
return _companyRepository.GetAll().Where(company => company.Id == Id)
.SelectMany(company => company.offices)
.Where(o => o.IsActive)
.SelectMany(office => office.People)
.Where(p => p.IsFired)
.Include(person => person.Children)
.ToList();
This creates a List with persons, including their children.
The last include controls says, all the children are loaded with this query. If you remove this include, you still can access the children, but than it is load-on-demand or lazy-loading. You will not notice any difference in the functions of your program, but in the communication with your sql-server.
I'm looking for the most elegant/best way to load navigation properties after creating an entry.
The situation is this:
*I create a row in my table and link 2 other tables by ID. The object I get back only contains the id's, not the actual linked objects.
*Through eager loading I want to load those objects
context.Entry(b)
.Reference(e => e.Table1)
.Reference(e => e.Table2)
.Load();
Doesn't seem to work, I can't chain References, so I could either query the complete object:
context
.Objects
.Where(o => o.ID == id)
.Include(o => o.Table1)
.Include(o => Table2)
.FirstOrDefault();
or do this :
context.Entry(b)
.Reference(e => e.Table1)
.Load();
context.Entry(b)
.Reference(e => e.Table2)
.Load();
But this creates (I suspect) 2 calls to the database instead of 1 combined call. Or am I missing another way to chain those references?
For this specific scenario you can use simple anonymous type projection and rely on the navigation property fix-up as described in Loading Related Data:
Tip
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.
So the following would do the job:
context.Objects
.Where(o => o.ID == id)
.Select(o => new { o.Table1, o.Table2 })
.Load();
and in theory should be better (should load only the related data). However, due to a current (v1.1.0) EF Core bug it would also include all the root object fields, thus making it equivalent of the variant with Includes:
context.Objects
.Where(o => o.ID == id)
.Include(o => o.Table1)
.Include(o => o.Table2)
.Load();
I personally would use the first method because the bugs hopefully will be fixed in some future EF Core release, while the second method behavior is "by design".
I have Parent and Child entities related to each other as 1 to M. I need to query childs together with parents within a single SQL query, but the Include method is not properly working for some cases.
This one makes a correct single query for both Parent and Child tables (via JOIN):
var r1 =
ctx.Set<Parent>()
.Include(p => p.Childs)
.Where(p => p.Id == 1)
.ToList();
Once i create an anonymous object on the fly, children are getting lost and SQL contains only Parent's fields. Retrieval of children remains lazy - they are still not loaded:
var r2 =
ctx.Set<Parent>()
.Include(p => p.Childs)
.Where(p => p.Id == 2)
.Select(p => new { myParent = p})
.ToList();
Questions:
Why it's so?
How can I construct a new anonymous object in my LINQ so childs are not geting lost?
p.s. i'd like keep Childs property of Parent virtual.
This is a general problem in all versions of EF known to me. EF tries hard to pass the 'includes' as far as possible, but when "the shape of the query changes", the 'includes' are irreversibly lost.
The "shape" of the query changes for example, when:
a projection is used (select not whole object but just some fields, or different object)
a group-by or other aggregation is used
.. and probably in some more cases, which currently I dont remember.
Sadly, I also dont remember where on MSDN I stumbled upon the "shape of the query" explanation. If I find it, I'll drop here a link.
The solution is actually quite simple: simply specify the 'include' part not early, but at the final result. So, instead of set.include(x) at beginning, do .Select( .. => new { .., x }) to include the 'x' manually. It also works during grouping, as you can do a projection there too.
However, this is not a solution. This is a manual patch/hotfix, which does not solve anything. Considering that you might want to expose a "IQueryable<>" through some interface, you may like to expose a "base query" with some things already .Included. And of course, this is simply not possible to do in a general way, as if the client of the interface does a projection or grouping, he will lose the includes and he will not even know which ones should be. For me, this is a major deficiency in EF.
EDIT: just found one: .Include in following query does not include really Not MSDN, but just as good.
As you're creating an anonymous object the Parent DbSet Set<Parent>() of the context is not being populated with any data and therefore neither are the Children being stored in the context. One solution could be to add the children to the anonymous object but I'm not sure this would cause them to be added to the Set<Child> DbSet.
var r2 = ctx.Set<Parent>()
.Include(p => p.Childs)
.Where(p => p.Id == 2)
.Select(p => new { myParent = p, children = p.Childs })
.ToList();
I have this line of code that selects a workflow status and then gets the next workflow statuses mapped to it.
status = db.WorkflowStatuses
.Include(x => x.CurrentMappings.Where(y => y.IsActive && y.NextWorkflowStatus.IsActive))
.Include(x => x.CurrentMappings.Select(y => y.NextWorkflowStatus).Where(y => y.IsActive))
.FirstOrDefault(x => x.Id == id);
My question is do I need the second Include since I referenced NextWorkflowStatus in the first Include?
Include represents eager loading and eager loading in EF doesn't support filtering or ordering so your code will not work at all. You cannot use Where inside include call.