I'm not the greatest with LINQ, but I'm trying to retrieve all the ModuleAvailabilities where the academicYear is the current year.
Are there any improvements to be made here?
pathway.PathwayFoundationModule.Attach(
pathway.PathwayFoundationModule.CreateSourceQuery()
.Include("Module")
.Include("Module.ModuleAvailabilities.Location")
.Where(o => o.Module.ModuleAvailabilities
.Where(x => x.AcademicYear == academicYear.Current)
.Count() >= 0)
);
I think you mean
pathway.PathwayFoundationModule.Attach(
pathway.PathwayFoundationModule.CreateSourceQuery()
.Include("Module")
.Include("Module.ModuleAvailabilities.Location")
.Where(o => o.Module.ModuleAvailabilities
.Any(x => x.AcademicYear == academicYear.Current));
Related
I'm not entirely sure how to translate the following SQL into LINQ Fluent API. Any help would be great
select count(distinct thread.Id) as ThreadCount, count(distinct segment.Id) as SegmentCount
from Segment
inner join SegmentCommunicator as SegmentCommunicator
on Segment.Id = SegmentCommunicator.SegmentId
inner join Thread
on Thread.Id = Segment.ThreadId
where SegmentCommunicator.CommunicatorId in (94, 3540, 6226, 10767, 20945)
Currently, I know how to do this in 2 queries but for the life of me I can't figure out how to condense down into one. Any help would be much appreciated
var aggregate1 = _threadProvider
.AsQueryable()
.SelectMany(t => t.Segments)
.Where(s => s.SegmentCommunicators.Any(sc => communicatorIds.Contains(sc.CommunicatorId)))
.Select(s => s.ThreadId)
.Distinct()
.Count();
var aggregate2 = _threadProvider
.AsQueryable()
.SelectMany(t => t.Segments)
.Where(s => s.SegmentCommunicators.Any(sc => communicatorIds.Contains(sc.CommunicatorId)))
.Select(s => s.Id)
.Distinct()
.Count();
You can use one "base" query but the two distinct counts will be separate queries, hydrating the query once with as small of a data set as possible:
var query = _threadProvider
.AsQueryable()
.SelectMany(t => t.Segments)
.Where(s => s.SegmentCommunicators.Any(sc => communicatorIds.Contains(sc.CommunicatorId)))
.Select(s => new {s.ThreadId, s.Id})
.Distinct()
.ToList();
var aggregate1 = query.Select(s => s.ThreadId)
.Distinct()
.Count();
var aggregate2 = query.Select(s => s.Id)
.Distinct()
.Count();
You might be able to use GroupBy to do it in one query:
var query = _threadProvider
.AsQueryable()
.SelectMany(t => t.Segments)
.Where(s => s.SegmentCommunicators.Any(sc => communicatorIds.Contains(sc.CommunicatorId)))
.GroupBy(s => 1)
.Select(g => new
{
ThreadCount = g.Select(s => s.ThreadId.Distinct().Count()),
SegmentCount = g.Select(s => s.Id.Distinct().Count()),
});
but I doubt that the underlying query provider will support it (at best it will turn it into two sub-queries).
Note that neither query will likely perform as fast as the raw SQL, since SQL can optimize the query before returning the results to Linq.
I have a Linq expression that is used in a few places. I went down the expression route as there wasn't a logical way to accomplish some searching logic without enumerating a very large table otherwise.
private Expression<Func<Property, bool>> PropertyIsCompliant()
{
return (p) => p.CalculationSets.OfType<SingleDocumentCalculationSet>()
.GroupBy(cs => cs.SourceDocument)
.Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
.SelectMany(cr => cr)
.All(cr => cr.Outcome == CalculationOutcome.Success);
}
My models are as such:
A Property has many CalculationSets
Each CalculationSet is also assigned to a Document
Each CalculationSet has a number of CalculationResults
Each CalculationResult has an Outcome
I'm trying to create an expression that will tell me if all the outcomes from the most recent calculationsets grouped by document ordered by most recent (ie the most recent distinct results) are Successful.
I can the SelectMany clause returns all the CalculationResults from the correct CalculationSets.
I just cant figure out how to return true ONLY if the collection isn't empty AND they are all Outcome.Success.
I understand the All operator automatically returns true on an empty collection. I just can't think of a way around it!
So your real condition is that there are not any unsuccessful outcomes. In that case use Any and reverse the condition:
//V-- notice the ! inverse operator here
return (p) => !(p.CalculationSets.OfType<SingleDocumentCalculationSet>()
.GroupBy(cs => cs.SourceDocument)
.Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
.SelectMany(cr => cr)
.Any(cr => cr.Outcome != CalculationOutcome.Success));
var countsBySuccess =
...
.GroupBy(cr => cr.Outcome == CalculationOutcome.Success) //group on success
.Select(g => new { IsSuccessful = g.Key, Count = g.Count() });
You can now examine the two result rows to make sure that the unsuccessful count is zero and the successful count is non-zero.
Regarding performance, this will need to materialize the entire result set server-side and aggregate it. But it does so only once.
If you must use the calculation result as part of a bigger query, you must use another trick:
!countsBySuccess.Any(g =>
g.IsSuccessful && Count == 0 ||
!g.IsSuccessful && Count != 0)
This boolean expression determines whether the condition you are looking for holds with one scan of the data.
It is important to only scan the data once. Do not simply write:
myItems.All(cr => cr.Outcome == CalculationOutcome.Success) && myItems.Any()
Because that does two scans. SQL Server does not optimize this out.
I think you're answering your question - if you know that All returns TRUE for empty then you have two checks to make. Excuse my C# (I'm not sure on the var query assignment, hopefully you get the idea) but you could do something like this:
private Expression<Func<Property, bool>> PropertyIsCompliant()
{
var query = (p) => p.CalculationSets.OfType<SingleDocumentCalculationSet>()
.GroupBy(cs => cs.SourceDocument)
.Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
.SelectMany(cr => cr);
return (query.Count > 0) & query.All(cr => cr.Outcome == CalculationOutcome.Success);
}
I didn't realise it was possible to use "&&" in expressions. So I've managed to combine 2 separate expressions that give the answer I need. The "&&" only returns true when both expressions evaluate "true"
return (p) =>
p.CalculationSets.OfType<SingleDocumentCalculationSet>()
.GroupBy(cs => cs.SourceDocument)
.Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
.SelectMany(cr => cr).Any()
&&
p.CalculationSets.OfType<SingleDocumentCalculationSet>()
.GroupBy(cs => cs.SourceDocument)
.Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
.SelectMany(cr => cr)
.All(cr => cr.Outcome == CalculationOutcome.Success);
I have an xml document
<NumSet>
<num>1</num>
<num>2</num>
<num>2</num>
<num>3</num>
</NumSet>
I want unique elements shown up, ie 1 and 3. not distinct which will also bring out 2.
How to do that? Do I have to use Group? Is there any concise way to do that?
You are right, you can use GroupBy and filter group which has only one item by using Count() == 1:
var output = XDocument.Load(xmlFile)
.Descendants("num")
.Select(e => e.Value)
.GroupBy(x => x)
.Where(g => g.Count() == 1)
.Select(g => g.Key);
It sounds like you want a Distinct GroupBy query... Take a look at the Need help on Linq with group by and distinct post here on StackOverflow.
XElement xe = XElement.Parse(#"<NumSet><num>1</num><num>2</num><num>2</num><num>3</num></NumSet>");
var query = xe.Elements("num")
.GroupBy(x => x.Value)
.Where(x=>x.Count ()==1)
.Select (x => x);
To do what you need I'd say that yes, you need to use GrouBy, and then count the elements in each group, and return those that contains just one element. In code, this translates to:
var query = lst.GroupBy(x => x)
.Where(x => x.Count() == 1)
.Select(x => x.Key);
Earlier I put a question on Stackoverflow about how to remove duplicate records in a list of objects, based on a particular property within each object.
I got the answer I was looking for (see below), a query which returns a distinct list of objects using MainHeadingID as the property to remove duplicates.
public IList<tblcours> GetAllCoursesByOrgID(int id)
{
return _UoW.tblcoursRepo.All.
Where(c => c.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id))
.GroupBy(c => c.MainHeadingID)
.Select(g => g.FirstOrDefault())
.ToList();
}
However, now I need more help! Is there anyway of amending the query above so that, it only removes duplicate values when MainHeadingID is not equal to 180. I tried amending GroupBy line to
.GroupBy(c => c.MainHeadingID != 180)
However, this didn't work.
Any help would be much appreciated with this.
Thanks.
Following works for LINQ to SQL:
return _UoW.tblcoursRepo.All
.Where(c => c.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id))
.GroupBy(c => c.MainHeadingID)
//.SelectMany(g => g.Key == 180 ? g : g.Take(1))
.SelectMany(g => g.Take(g.Key == 180 ? Int32.MaxValue : 1))
.ToList();
Comments: SelectMany in query above selects all items from group where MainHeadingID equals to 180, but it takes only one item form other groups (i.e. distinct result). Linq to SQL cannot translate commented out part, but thanks to #usr there is way around.
Linq to Entities cannot translate even simplified query. I think only option for you in this case is simple concating result of two queries:
Expression<Func<tblcours, bool>> predicate = x =>
x.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id)
int headingId = 180;
return _UoW.tblcoursRepo.All
.Where(c => c.MainHeadingID != headingId)
.Where(predicate)
.GroupBy(c => c.MainHeadingID)
.Select(g => g.FirstOrDefault())
.Concat(_UoW.tblcoursRepo.All
.Where(c => c.MainHeadingID == headingId)
.Where(predicate))
.ToList();
lazyberezovsky's answer fails due to an EF bug (which is not surprising given the quality of EF's LINQ support). It can be made to work with a hack:
.SelectMany(g => g.Key == 180 ? g.Take(int.MaxValue) : g.Take(1))
or
.SelectMany(g => g.Take(g.Key == 180 ? int.MaxValue : 1))
Note that performance will not be particularly good due to the way this is translated to SQL.
How can I find the Min value of a RavenDB document property over all documents that satisfy a condition.
For example, I want to find what is the earliest release date of all movie documents in the ravendb database that belong NY state.
I wrote something like this.. please correct me.. I need help at "??????" in the following query...
DateTime EarliestDate = session.Query<Movie>()
.Where(x => x.State == "NY")
.GroupBy(x => x.ReleaseDate)
.Select????Min(x => x.ReleaseDate));
I may be wrong, but don't you just want this:
DateTime EarliestDate = session.Query<Movie>()
.Where(x => x.State == "NY")
.Min(x => x.ReleaseDate);
UPDATE:
try this
DateTime EarliestDate = session.Query<Movie>()
.Where(x => x.State == "NY")
.OrderBy(x => x.ReleaseDate)
.Take(1)
.Select(x => x.ReleaseDate)
.FirstOrDefault();