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();
Related
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();
}
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.
I have a SQL Server table called ControlActivityChangeLog. The table has columns CurrentValue and NewValue, of which, both are nullable nvarchars. How do I query all ControlActivityChangeLogs but exclude results where CurrentValue and NewValue are null or empty. If CurrentValue is null or empty and NewValue is not then I need that record.
I tried adding this to the below query but it ends up returning no results:
!x.ControlActivityChangeLogs.Any(y => string.IsNullOrEmpty(y.CurrentValue) && string.IsNullOrEmpty(y.NewValue))
Here is my qry:
var qry = _context.ControlActivities
.Include(x => x.ControlActivityChangeLogs)
.Include(x => x.Company)
.Where(x =>
!x.IsDeleted &&
!x.IsArchived &&
!x.ControlActivityChangeLogs.Any(y => string.IsNullOrEmpty(y.CurrentValue) && string.IsNullOrEmpty(y.NewValue)))
.AsQueryable();
**OTHER COLUMN FILTERS HERE**
var results = await qry.Select(x => new ModifiedCAModel
{
**List Of Columns**,
Changes = x.ControlActivityChangeLogs
.Where(y => y => y.ControlActivityIssueId == null && y.ControlActivityTestId == null)
.OrderByDescending(y => y.ChangedDate)
.ToList()
}).ToListAsync();
The Where or Any condition is for including, so you need the inverse of
exclude results where CurrentValue and NewValue are null or empty
which is
include results where CurrentValue or NewValue is not null or empty
i.e. instead of
!x.ControlActivityChangeLogs.Any(y => string.IsNullOrEmpty(y.CurrentValue) && string.IsNullOrEmpty(y.NewValue)))
you need
x.ControlActivityChangeLogs.Any(y => !string.IsNullOrEmpty(y.CurrentValue) || !string.IsNullOrEmpty(y.NewValue)))
the below should be able to translate to SQL correctly
var qry = _(context.ControlActivities
.Include(x => x.ControlActivityChangeLogs)
.Include(x => x.Company)
.Where(x => !x.IsDeleted
&& !x.IsArchived
&& x.ControlActivityChangeLogs.CurrentValue != null
&& x.ControlActivityChangeLogs.CurrentValue != ""
&& x.ControlActivityChangeLogs.NewValue != null
&& x.ControlActivityChangeLogs.NewValue != ""
).AsQueryable();
you should check what sql is being executed tho!!!
this can be obtained but adding logging to ef.
I'm struggling to transform this piece of code in a single LINQ expression.
var x = values
.Where(v => v.Columns.Any(c => c.Code == code && c.Value == value))
.Select(v => v.Value)
.FirstOrDefault();
if (x == null)
{
x = values
.Where(v => v.Columns.All(c => string.IsNullOrEmpty(c.Code))
.Select(v => v.Value)
.FirstOrDefault();
}
Basically I have a list of objects. Each objects contains a list of Column objects and a Value.
I want to filter the object that contains a specific Column object (based on Code and Value), but if this combination does not exist, I want to fall back to the entity that contains a list of Column objects all having Code equals to string.Empty (a wild card).
I have tried different approches like the following but without success:
var x = values
.Where(v => v.Columns.Any(c => c.Code == code && c.Value == value)
? v.Columns.Any(c => c.Code == code && c.Value == value)
: v => v.Columns.All(c => string.IsNullOrEmpty(c.Code))
.Select(v => v.Value)
.FirstOrDefault();
I suggest Concat both alternatives:
var x = values
.Where(v => v.Columns.Any(c => c.Code == code && c.Value == value))
.Select(v => v.Value)
.Concat(values // second alternative if 1st returns empty cursor
.Where(v => v.Columns.All(c => string.IsNullOrEmpty(c.Code))
.Select(v => v.Value))
.FirstOrDefault();
Edit: You can simplify the query (see CSharpie's comment) by extracting .Select(v => v.Value) into
var x = values
.Where(v => v.Columns.Any(c => c.Code == code && c.Value == value))
.Concat(values // second alternative if 1st returns empty cursor
.Where(v => v.Columns.All(c => string.IsNullOrEmpty(c.Code)))
.Select(v => v.Value)
.FirstOrDefault();
You can use DefaultIfEmpty(fallback):
var fallBackValue = values
.Where(v => v.Columns.All(c => string.IsNullOrEmpty(c.Code))
.Select(v => v.Value)
.FirstOrDefault();
var x = values
.Where(v => v.Columns.Any(c => c.Code == code && c.Value == value))
.Select(v => v.Value)
.DefaultIfEmpty(fallBackValue)
.First(); // FirstOrDefault not nessesary anymore;
This has the advantage that you can even select multiple without breaking the logic, so the fallback value would still be returned if Take(3)(for example) would not return any items.
It is also efficient since the fallback value will be calculated independently of the main query and could be returned from a property, so that it needs to be initialized only once.
Another (similar option) is the null coalescing operator(if Value is a reference type):
var x = values
.Where(v => v.Columns.Any(c => c.Code == code && c.Value == value))
.Select(v => v.Value)
.FirstOrDefault() ?? fallBackValue;
But i'd prefer the first because it can be chained and also modified easily(i.e. Take(x)).
The code below work succesfully to find if a value exists in a list. How do I add a where clause such that only for list items where Type = "File"
if (MyGlobals.ListOfItemsToControl.Any(x => x.sItemName == info.FullName)) // Dont allow duplicates
{
}
Pseudo Code for what i want
if (MyGlobals.ListOfItemsToControl.Any(x => x.sItemName == info.FullName).Where(y => y.Type == "File")) // Dont allow duplicates
{
}
Your filter (Where) should be before Any
if (MyGlobals.ListOfItemsToControl
.Where(y => y.Type == "File")
.Any(x => x.sItemName == info.FullName))
You can also combine both conditions in Any like:
if (MyGlobals.ListOfItemsToControl
.Any(x => x.Type == "File"
&& x => x.sItemName == info.FullName))
instated of where you can simply use
if (MyGlobals.ListOfItemsToControl.Any(x => x.sItemName == info.FullName && x.Type == "File")) // Dont allow duplicates
{
}