If possible, please guide me how to convert my SQL command to lambda expression
select d.* from takcontractdet d where d.contractid=pubcontractid and d.personid in
(
select p.id from personel p where p.parentid=pubparentid)
)
Two query
var personelIds = Personels.Where(p => p.ParentId == pubparentid)
.Select(e => e.Id).ToList();
var result = Takcontractdets.Where(d => d.contractid == pubcontractid &&
personelIds.Contains(d.PersonId)).ToList();
One query
var result = Takcontractdets.Where(d => d.contractid == pubcontractid &&
Personels.Where(p => p.ParentId == pubparentid)
.Select(e => e.Id).ToList().Contains(d.PersonId))
.ToList();
Context: The webapplication is some sort of Reddit with Tags.
I have the following include initialisation which returns a IQueryable:
IQueryable<Item> items = itemRepository
.Include( //.Actions
el => el.Votes,
el => el.Comments,
el => el.CreatedBy.Roles,
el => el.TagItems.Select(dl => dl.Tag.Actions))
.Where(el => el.SiteId == siteId && el.Status >= 0)
.OrderBy(orderBy).AsNoTracking();
The IQueryable is later used with ExpressionBuilder (LinqKit), because there are a lot of AND / OR queries.
When i use the personal mode on my application ( = show only results that a user upvoted/created or results from the tags that the user is following), the query becomes really slow:
if (filterBy.PersonalMode)
{
// || el.TagItems.Any(dl => dl.Tag.UserId == filterBy.UserId)
itemPredicate = itemPredicate.And(el =>
el.Votes.Select(dl => new { UserId = dl.UserId}).Any(dl =>
dl.UserId == filterBy.UserId)
|| el.CreatedById == filterBy.UserId
|| (filterBy.RoleId.HasValue && el.TagItems.Select(dl => new { UserRoleId = dl.Tag.UserRoleId, PersonalTags = dl.Tag.PersonalTags }).Any(dl => dl.UserRoleId.HasValue && filterBy.RoleId.HasValue && dl.UserRoleId.Value == filterBy.RoleId.Value))
|| el.TagItems.Any(dl => dl.Tag.PersonalTags.Select(cl => new { UserId = cl.UserId }).Any(cl => cl.UserId == filterBy.UserId)));
}
I'm trying to stay away from alternatives from EF, because it keeps my code pretty clean to read.
The query itselve, mentions a 61% execution time.
Execution plan XML:
https://www.brentozar.com/pastetheplan/?id=ry9najEMr
Slow part:
Output list
[handlr].[dbo].[Tags].Id; [handlr].[dbo].[Tags].Name; [handlr].[dbo].[Tags].SiteId; [handlr].[dbo].[Tags].Active; [handlr].[dbo].[Tags].CreatedOn; [handlr].[dbo].[Tags].FillsInParentTag; [handlr].[dbo].[Tags].ShowOnOverview; [handlr].[dbo].[Tags].ParentTagId; [handlr].[dbo].[Tags].LeftBower; [handlr].[dbo].[Tags].RightBower; [handlr].[dbo].[Tags].Depth; [handlr].[dbo].[Tags].Caption; [handlr].[dbo].[Tags].isRestricted; [handlr].[dbo].[Tags].Description; [handlr].[dbo].[Tags].ShowTag; [handlr].[dbo].[Tags].Count; [handlr].[dbo].[Tags].UserId; [handlr].[dbo].[Tags].UserRoleId; [handlr].[dbo].[Tags].SynonymOfTagId
Visual:
Any advice on how to improve this query? Adding non-clustured indexes don't seem to do much currently.
I am facing this linq query for entity framework core (2.0).
var result = await dbContext.Table1DbSet
.Where(t1e => t1e.Id == id && t1e.Id2 == id2)
.Select
(
t1e =>
t1e.Table2NavPropICollection.Select
(
t2e => new
{
singleObject = t2e.Table3NavPropObject.TargetObject,
enumerable1 = t2e.Table3NavPropObject.Table4NavPropObject.Table5NavPropICollection.Select(t5e => t5e.TargetObject),
enumerable2 = t2e.Table3NavPropObject.Table6NavPropObject.Table7NavPropICollection.Select(t7e => t7e.TargetObject),
enumerable3 = t2e.Table3NavPropObject.Table8NavPropICollection.SelectMany(t8e => t8e.Table9NavPropICollection.Select(t9e => t9e.TargetObject))
}
)
)
.ToListAsync();
The goal is to query all the referenced instances of TargetObject which is referenced accros ~ 10 different tables.
Currently it returns an IEnumerable where the anonymous object contains the properties singleObject, enumerable1, enumerable2, enumerable3. All those properties are of type TargetObject or IEnumerable.
Can I, and how, rewrite the query to not return anonymous objects but just an IEnumerable containing all the values?
For some reason the compiler won't let me iterate over the anonymous collection and flatten it manually.
This should do the trick if you want one array per t1e row.
var result = await dbContext.Table1DbSet
.Where(t1e => t1e.Id == id && t1e.Id2 == id2)
.Select
(
t1e =>
t1e.Table2NavPropICollection.Select
(
t2e => new[] {t2e.Table3NavPropObject.TargetObject}.Concat(
t2e.Table3NavPropObject.Table4NavPropObject.Table5NavPropICollection.Select(t5e => t5e.TargetObject)).Concat(
t2e.Table3NavPropObject.Table6NavPropObject.Table7NavPropICollection.Select(t7e => t7e.TargetObject)).Concat(
t2e.Table3NavPropObject.Table8NavPropICollection.SelectMany(t8e => t8e.Table9NavPropICollection.Select(t9e => t9e.TargetObject)))
)
)
.ToListAsync();
If you want it completely flat, you'll want to switch that Select to a SelectMany().
var result = await dbContext.Table1DbSet
.Where(t1e => t1e.Id == id && t1e.Id2 == id2)
.SelectMany
(
t1e =>
t1e.Table2NavPropICollection.Select
(
t2e => new[] {t2e.Table3NavPropObject.TargetObject}.Concat(
t2e.Table3NavPropObject.Table4NavPropObject.Table5NavPropICollection.Select(t5e => t5e.TargetObject)).Concat(
t2e.Table3NavPropObject.Table6NavPropObject.Table7NavPropICollection.Select(t7e => t7e.TargetObject)).Concat(
t2e.Table3NavPropObject.Table8NavPropICollection.SelectMany(t8e => t8e.Table9NavPropICollection.Select(t9e => t9e.TargetObject)))
)
)
.ToListAsync();
Is Add and/or Concat a possible solution?
PoC:
var a = new [] { 1,2,3 };
var result = new {
firstA = a.First(),
otherAs = a,
backwards = a.Reverse()
};
var final = new List<int>();
final.Add(result.firstA);
final.Concat(result.otherAs.Concat(result.backwards))
.Dump();
I have two Entities EntityTest and EntityRelated.
I want to query and get results from both Entites where Deleted is not true in both Entites.
I have tries below statement. It return EntityTest records by excluding records having Deleted = true but records of EntityRelated are not filtered.
db.EntityTest
.Include(i => i.EntityRelated)
.Where(x => x.Deleted != true && x.EntityRelated.Any(a => a.Deleted != true).ToList();
Solution 1: Use this implementation of an extension method Include2() Include2. as following:
db.EntityTest
.Include(i => i.EntityRelated.Where(e=>e.Deleted == false))
.Where(x => x.Deleted != true && x.EntityRelated.Any(a => a.Deleted != true)
.ToList();
Solution 1:
I cannot rewrite the current DB schema right now BTW, but that's beside the point to the issue I've hit, so please ignore the table structure :D
I'm running this DB query:
my $rs = $dbx->resultset('Result')->search(
{
'result_hnd' => 16078055,
'seasons.outdoor' => 'venue.outdoors',
'seasons.start_date' => { '<=' => 'meet.date_end' },
'seasons.end_date' => { '>=' => 'meet.date_begin' },
},
{
'join' => [
{
'team' => {
'league_teams' => {
'league' => 'seasons',
},
},
},
{
'meet' => 'venue'
},
],
'+select' => ['seasons.season_hnd','seasons.name','seasons.start_date','seasons.end_date','meet.date_begin','meet.date_end'],
'+as' => ['season_hnd','season_name','s_start','s_end','m_start','m_end'],
columns => ['result_hnd'],
group_by => ['seasons.season_hnd'],
}
);
When I run this, I get no results. With DBIC_TRACE on, I see the generated SQL as:
SELECT me.result_hnd, seasons.season_hnd, seasons.name, seasons.start_date, seasons.end_date, meet.date_begin, meet.date_end FROM track.result me JOIN track.team team ON team.team_hnd = me.team_hnd LEFT JOIN track.league_team league_teams ON league_teams.team_hnd = team.team_hnd LEFT JOIN track.league league ON league.league_hnd = league_teams.league_hnd LEFT JOIN track.season seasons ON seasons.league_hnd = league.league_hnd OR seasons.league_hnd = league.parent_league_hnd JOIN track.meet meet ON meet.meet_hnd = me.meet_hnd JOIN track.venue venue ON venue.venue_hnd = meet.venue_hnd WHERE ( ( result_hnd = ? AND seasons.end_date >= ? AND seasons.outdoor = ? AND seasons.start_date <= ? ) ) GROUP BY seasons.season_hnd: '16078055', 'meet.date_begin', 'venue.outdoors', 'meet.date_end'
When I copy and paste this statement into my MYSQL client (and interpolate the placeholders), like this:
SELECT me.result_hnd, seasons.season_hnd, seasons.name, seasons.start_date, seasons.end_date, meet.date_begin, meet.date_end
FROM track.result me
JOIN track.team team ON team.team_hnd = me.team_hnd
LEFT JOIN track.league_team league_teams ON league_teams.team_hnd = team.team_hnd
LEFT JOIN track.league league ON league.league_hnd = league_teams.league_hnd
LEFT JOIN track.season seasons ON seasons.league_hnd = league.league_hnd OR seasons.league_hnd = league.parent_league_hnd
JOIN track.meet meet ON meet.meet_hnd = me.meet_hnd
JOIN track.venue venue ON venue.venue_hnd = meet.venue_hnd
WHERE ( ( result_hnd = 16078055 AND seasons.end_date >= meet.date_begin AND seasons.outdoor = venue.outdoors AND seasons.start_date <= meet.date_end ) )
GROUP BY season_hnd;
I get the exact result I expect (7 records).
This is really bizarre. To all intents and purposes, isn't that exactly the same query? Am I missing something in my debugging? Or is something else happening at the DBIx::Class::ResultSet layer that isn't being dumped?
To tell SQL::Abstract that the value on the right is actually an identifier, you can do the following (as outlined in the docs):
{
'result_hnd' => 16078055,
'seasons.outdoor' => { -ident => 'venue.outdoors' },
'seasons.start_date' => { '<=' => { -ident => 'meet.date_end' } },
'seasons.end_date' => { '>=' => { -ident => 'meet.date_begin' } },
},
To all intents and purposes, isn't that exactly the same query?
(For all intents and purposes, ...)
No. In the log, you have something equivalent to
result_hnd = '16078055'
AND seasons.end_date >= 'meet.date_begin'
AND seasons.outdoor = 'venue.outdoors'
AND seasons.start_date <= 'meet.date_end'
or maybe
result_hnd = 16078055
AND seasons.end_date >= 'meet.date_begin'
AND seasons.outdoor = 'venue.outdoors'
AND seasons.start_date <= 'meet.date_end'
In your attempt, you used
result_hnd = 16078055
AND seasons.end_date >= meet.date_begin
AND seasons.outdoor = venue.outdoors
AND seasons.start_date <= meet.date_end
Sorry, I don't have the solution for you.