HI all i have below two methods and looking to combine both and one method does not need any joins and other method need those how can i combine these two methods
internal static IQueryable<ConstructionSet> CalculateSelectedConstructionSetsForOSM(Guid? ashraeClimateZoneId,
Guid? energyCodeId,
Guid? massingTypeId,
APIDbContext dbContext)
{
if (dbContext is null)
{
throw new ArgumentNullException(nameof(dbContext));
}
return dbContext.ConstructionSets.Include(p => p.AshraeClimateZone)
.Include(p => p.MassingType)
.Include(p => p.SourceOfData)
.Include(p => p.ExteriorWall)
.Include(p => p.ExteriorFloor)
.Include(p => p.InteriorFloor)
.Include(p => p.InteriorWall)
.Include(p => p.SlabOnGrade)
.Include(p => p.BelowGradeWall)
.Include(p => p.Glazing)
.Include(p => p.Roof)
.Where(p => p.AshraeClimateZoneId == ashraeClimateZoneId
&& p.SourceOfDataId == energyCodeId
&& p.MassingTypeId == massingTypeId
&& p.Revision != null
&& p.IsApproved == true)
.AsEnumerable()
.OrderByDescending(i => i.Revision)
.GroupBy(i => i.InitialRevisionId)
.Select(g => g.First()).AsQueryable();
}
the below one is another method
internal static IQueryable<ConstructionSet> CalculateSelectedConstructionSetsForProject(Guid? ashraeClimateZoneId,
Guid? energyCodeId,
Guid? massingTypeId,
APIDbContext dbContext)
{
if (dbContext is null)
{
throw new ArgumentNullException(nameof(dbContext));
}
return dbContext.ConstructionSets.Include(p => p.AshraeClimateZone)
.Include(p => p.MassingType)
.Include(p => p.SourceOfData)
.Where(p => p.AshraeClimateZoneId == ashraeClimateZoneId
&& p.SourceOfDataId == energyCodeId
&& p.MassingTypeId == massingTypeId
&& p.Revision != null
&& p.IsApproved == true)
.AsEnumerable()
.OrderByDescending(i => i.Revision)
.GroupBy(i => i.InitialRevisionId)
.Select(g => g.First()).AsQueryable();
}
Could any one please let me know how can i combine these methods, many thanks in advance.
Assuming by "combine them" you mean "refactor them so a single method can handle both cases", you can do something like this:
internal static IQueryable<ConstructionSet> CalculateSelectedConstructionSets(Guid? ashraeClimateZoneId,
Guid? energyCodeId,
Guid? massingTypeId,
APIDbContext dbContext,
bool includeOsmNavigationProperties)
{
if (dbContext is null)
{
throw new ArgumentNullException(nameof(dbContext));
}
var sets = dbContext.ConstructionSets.Include(p => p.AshraeClimateZone)
.Include(p => p.MassingType)
.Include(p => p.SourceOfData);
if(includeOsmNavigationProperties)
{
sets = sets.Include(p => p.ExteriorWall)
.Include(p => p.ExteriorFloor)
.Include(p => p.InteriorFloor)
.Include(p => p.InteriorWall)
.Include(p => p.SlabOnGrade)
.Include(p => p.BelowGradeWall)
.Include(p => p.Glazing)
.Include(p => p.Roof);
}
return sets.Where(p => p.AshraeClimateZoneId == ashraeClimateZoneId
&& p.SourceOfDataId == energyCodeId
&& p.MassingTypeId == massingTypeId
&& p.Revision != null
&& p.IsApproved == true)
.AsEnumerable()
.OrderByDescending(i => i.Revision)
.GroupBy(i => i.InitialRevisionId)
.Select(g => g.First()).AsQueryable();
}
As a side note, you should avoid the pattern of converting this to .AsEnumerable() and then back to .AsQueryable(). Making the result an IQueryable makes subsequent operations on the returned collection much slower (expressions need to be compiled at run-time), and it hides the fact that you won't be performing subsequent operations at the database layer. Someone might add a Where() clause and not realize that they're still causing the entire set of data to get loaded out of the database.
Related
I have some troubles with using LINQKit library in order to include dynamic filters in my queries.
To begin with, I would like to share with a type of filter that is being sent to my query:
public Expression<Func<JobSpecificationDetail,bool>> Criteria { get; set; }
Next, I have my query which simply executes the following piece of code:
var queryTest = applicantCacheRepo
.AsNoTracking()
.Include(a => a.Profile)
.ThenInclude(p => p.ProfileEmployer)
.ThenInclude(p => p.Employer)
.Include(a => a.ProfileApplicationDetail)
.ThenInclude(p => p.ApplicationStatusSysCodeUnique)
.Include(a => a.Person)
.ThenInclude(p => p.PersonDetail)
.Include(a => a.JobSpecification)
.ThenInclude(j => j.JobSpecificationDetail)
.Where(a => filters.ManagerFilter.Invoke(a.Profile)
&& filters.ApplyDateFilter.Invoke(a.ProfileApplicationDetail)
&& filters.StatusDateFilter.Invoke(a.ProfileApplicationDetail)
&& filters.IsTopFilter.Invoke(a.ProfileApplicationDetail)
&& !a.ProfileApplicationDetail.ApplicationStatusSysCodeUnique.Deleted
&& a.Person.Deleted == false
&& a.Profile.Deleted == false
&& a.JobSpecification.JobSpecificationDetail
.Any(jd=>filters.JobSpecificationDetailSpec.Criteria.Invoke(jd)) //this line results in aforementioned exception
&& a.Profile.ProfileTypeSysCodeUniqueId == SysCodeUniqueId.ProfileType.EmployeeApplicant
&& !a.ProfileApplicationDetail.Deleted
).OrderByDescending(a => a.ApplyDate);
So, here in the query, the part which is indicated with a comment, throws that exception. I do not know what to do. In the query, you can find implementation of LINQKit methods as well. They do not create any problems.
How to simplify the next query to database:
public Plan? Get(DateTime now)
{
return context.Plans
.Where(x => IsActivePlan(x, now)) // 1 condition
.Where(x => IsPlolongingPlan(x, now)) // 2 condition
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
}
What I need:
If there are objects after 1 condition, then execute "OrderBy" and return the first element. If there are no objects, then go to the 2 condition, execute "OrderBy" and return "FirstOrDefault". I don't want the objects to be taken at once by two conditions.
Thank you
something like this
public Plan? Get(DateTime now)
{
return context.Plans.Where(x => IsActivePlan(x, now)).OrderBy(x => x.StartedAt).FirstOrDefault()
?? context.Plans.Where(x => IsPlolongingPlan(x, now)).OrderBy(x => x.StartedAt).FirstOrDefault();
}
because you don't want two conditions been true at once you have to:
return context.Plans
.Where(x => (IsActivePlan(x, now) && !IsPlolongingPlan(x, now)) ||
(!IsActivePlan(x, now) && IsPlolongingPlan(x, now)))
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
You can check before if exist any
Like this:
var result = null;
if (context.Plans.Any(x => IsActivePlan(x, now)))
{
result = context.Plans.Where(x => IsActivePlan(x, now))
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
}
else
{
result = context.Plans.Where(x => IsPlolongingPlan(x, now))
.OrderBy(x => x.StartedAt)
.FirstOrDefault();
}
I do have a complex query to select a full object called Performance
The Performance relationship with others objects is:
Performance has a list of Index
Index has a list of SubIndex
SubIndex has a list of Indicator
Indicator has a list of Item
Item relationship with Spot and Measurement:
Item has one Spot and one Measurement
The query below returns exactly what I want, but I would like to include the Spot and Measurement to the Item object.
return _context.Performance.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items))))
.SingleOrDefault(p => p.Id == id);
I have tried the query below and it is returning the Measurement object. How to include the Spot object?
return _context.Performance.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items.Select(tm => tm.Measurement)))))
.SingleOrDefault(p => p.Id == id);
You could add second Include too;
return _context.Performance.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items.Select(tm => tm.Measurement)))))
.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items.Select(tm => tm.Spot)))))
.SingleOrDefault(p => p.Id == id);
I need to return all objects that have child objects with a certain field != null.
NOTE: EpicStoryId is nullable int (as in 'int?')
I have tried:
return _context.Features
.Where(x => x.UserStories.Any(us => us.EpicStoryId.HasValue)
&& x.Id == Id)
.FirstOrDefault();
and I have tried:
return _context.Features
.Where(x => x.UserStories.Any(us => us.EpicStoryId != null)
&& x.Id == Id)
.FirstOrDefault();
and for good measure:
return _context.Features
.Where(x => x.UserStories.Any(us => us.EpicStoryId.HasValue == false)
&& x.Id == Id)
.FirstOrDefault();
and finally:
return _context.Features
.Where(x => x.UserStories.Any(us => us.EpicStoryId > 0)
&& x.Id == Id)
.FirstOrDefault();
But none of these work. It's still returning every 'Feature' with Id=Id regardless if a child has a value for EpicStoryId or not. (FYI, I checked the data and there ARE null values for some EpicStoryId's.)
sample data:
Any will return true i any 1 EpicStoryId has value so your your condition is failing.
All should do:-
return _context.Features
.FirstOrDefault(x => x.UserStories.All(us => us.EpicStoryId.HasValue)
&& x.Id == Id);
If you need to return all objects then don't use FirstOrDefault(), use combination of .Where() and .ToList() methods :
For any of us EpicStoryIds are not null use :
return _context.Features
.Where(x => x.Id == Id && x.UserStories.Any(us => us.EpicStoryId.HasValue))
.ToList();
For all of us EpicStoryIds are not null you can use :
return _context.Features
.Where(x => x.Id == Id && x.UserStories.All(us => us.EpicStoryId.HasValue))
.ToList();
If you want to return list of UserStories and not Features, you can use :
return _context.Features
.Where(x => x.Id == Id)
.SelectMany(x => x.UserStories
.Where(us => us.EpicStoryId.HasValue))
.ToList();
I have this C# code that works, but I'd like to be able to choose the Agency if a person is in it all in the query. Is there a way to do that all in the query?
var retVal = new List<Agency>();
var items=_db.Agencies
.Include(x => x.AgencyMembers.Select(y => y.Person))
.Where(w => w.NationId == User.NationId).ToList();
foreach (var agency in items)
{
if(agency.AgencyMembers.Any(c=>c.Person.Id==personId))
retVal.Add(agency);
}
return retVal;
You should be able to just add that predicate to your query.
return _db.Agencies
.Include(x => x.AgencyMembers.Select(y => y.Person))
.Where(w => w.NationId == User.NationId)
.Where(agency => agency.AgencyMembers.Any(c=>c.Person.Id==personId))
.ToList();
Depending what navigation properties you have, you may be able to simplify it by starting from the person.
return _db.People
.Single(p => p.Id == personId)
.Agencies
.Where(w => w.NationId == User.NationId)
.ToList();
You can try this:
var items=_db.Agencies
.Include(x => x.AgencyMembers.Select(y => y.Person))
.Where(agency=> agency.NationId == User.NationId && agency.AgencyMembers.Any(c=>c.Person.Id==personId))
.ToList();