how to order a group result with Linq? - c#

How can I order the results from "group ... by... into..." statement in linq?
For instance:
var queryResult = from records in container.tableWhatever
where records.Time >= DateTime.Today
group records by tableWhatever.tableHeader.UserId into userRecords
select new { UserID = userRecords.Key, Records = userRecords };
The query returns records in table "contain.tableWhatever" grouped by "UserId". I want the returned results within each group ordered by time decending. How can I do that?
More specific, assume the above query return only one group like the following:
{UserID = 1, Records= {name1 5/3/2010_7:10pm;
name2 5/3/2010_8:10pm;
name3 5/3/2010_9:10pm} }
After insert the orderby statement in the above query, the returned results should be like this:
{UserID = 1, Records= {name3 5/3/2010_9:10pm;
name2 5/3/2010_8:10pm;
name1 5/3/2010_7:10pm} }
Thanks for help!

Simply use the OrderByDescending extension to order the records in the anonymous type.
var queryResult = from records in container.tableWhatever
where records.Time >= DateTime.Today
group records by tableWhatever.tableHeader.UserId into userRecords
select new
{
UserID = userRecords.Key,
Records = userRecords.OrderByDescending( u => u.Time )
};

could you do:
var queryResult = from records in container.tableWhatever
where records.Time >= DateTime.Today
group records by tableWhatever.tableHeader.UserId into userRecords
select new { UserID = userRecords.Key, Records = userRecords.OrderByDescending(r=>r.Time) };

Related

How to write subquery with the any quantifier using linq?

I have a problem with using any in linq I do not know how to do it correctly.
I have to write this in linq:
SELECT ename, job, deptno
FROM emp
WHERE sal > ANY
(
SELECT DISTINCT sal
FROM emp
WHERE deptno = 30
);
I write only this:
var min = (from emp in Emps
where emp.Deptno == 30
select emp.Sal
).Distinct();
var result = (from emp in Emps
where min.Any() > emp.Sal
select new
{
emp.Ename
});
Linq doesn't have an any/some operator in the way Sql Server does.
var salariesInTargetDepartment = Emps
.Where(x => x.Deptno == 30)
.Select(x => x.Sal)
.Distinct()
.ToList(); // the ToList is not required, but seeing you're going to be executing
// against this query many times, it will be better to cache the results.
var matchingEmployees = Emps
.Where(emp => salariesInTargetDepartment
.Any(target => emp.Sal > target)
);
The where clause in the second statement says "Only include this record if this record's Sal property is greater than at least one entry in the salariesInTargetDepartment collection."

Grouping on virtual (predefined) column in linq

I am trying to write a linq query for one of my dashboard which retrieves data based on some conditions. I want to display records count based on the different status available in my table.
Following is the SQL query in which I am trying to convert into Linq.
select count(id) cnt, 'Available' label from table where date = sysdate
Above query is returning below result in DB IDE. This is the result I want with linq
cnt label
0 Available
I've tried with following linq query but it is returning 0 count and hence result is not being retrieved.
var data = (from a in context
where a.date = System.DateTime.Now
group a in a.id into g
select new {
cnt = g.Count(),
label = 'Available'
}).ToList();
How do I achieve above mentioned result in linq. Your help will be appreciated.
Thanks
-------------EDIT----------------
Updated LINQ query
var data = (from a in context.TableA
where a.id = uniqueID
group a in a.id into g
select new {
cnt = g.Count(),
label = 'Available'
}).Concat(from a in context.TableB
where a.id = uniqueID
group a in a.id into g
select new {
cnt = g.Count(),
label = 'WIP'
}).ToList();
To count the number of elements matching a predicate in a linq query simply use the where clause:
var results =
from a in context
where a.date.Date == DateTime.Now.Date
&& a.id == someIdHere
select a;
var data = new {
count = results.Count(),
label = "Available"
};
Or, in extension method syntax (which I prefer):
var results = context.Where(a => a.date.Date == DateTime.Now.Date && a.id == someIdHere);
var data = new {
count = results.Count(),
label = "Available"
};
Also be careful when comparing a DateTime object with regards to what results you desire; comparing DateTime.Now to a date will likley return false since it will compare the time code as well, use the DateTime.Date property to obtain only the date from the object for the purposes of comparison.

Using linq to group, select, and order a datatable

I want to use Linq to select and group DataTable rows... and I want to order those in a descending manner by the "Max" created date in each group... are there any improvements that could be made to this code, in particular can I make the OrderByDescending part of the Linq, for example using:
orderby {... something here...} descending
--- current code ---
DataTable dt = ReadDataTable();
var rows = (from row in dt.AsEnumerable()
where row.Field<bool>("Active") == true
group row by new
{
CollectionId = row.Field<int>("CollectionId"),
CollectionName = row.Field<string>("CollectionName"),
} into grp
select new
{
CollectionId = grp.Key.CollectionId,
CollectionName = grp.Key.CollectionName,
MaxCreated = grp.Max(r => r.Field<DateTime>("Created"))
}).OrderByDescending(r => r.MaxCreated);
You can use the let clause to hold intermediate results in a complex LINQ query, for use in subsequent sorts and selects. In your case you can use it to store the final result for subsequent sorting.
I.e. you can rewrite your Linq without the OrderByDescending() lambda as follows:
DataTable dt = ReadDataTable();
var rows = from row in dt.AsEnumerable()
where row.Field<bool>("Active")
group row by new
{
CollectionId = row.Field<int>("CollectionId"),
CollectionName = row.Field<string>("CollectionName"),
} into grp
let result = new
{
CollectionId = grp.Key.CollectionId,
CollectionName = grp.Key.CollectionName,
MaxCreated = grp.Max(r => r.Field<DateTime>("Created")),
}
orderby result.MaxCreated descending
select result;

LINQ Count and Group by different Columns

id'like to count how many documents a User edited or created. Therefore I have a Datatable which contains the information sth. like this:
Input
DocumentName | ModifiedBy | CreatedBy
a Frank Frank
b Mike Frank
c John Mike
That should be the Output:
Name DocumentsModified(Total) DocumentsCreated(Total)
Frank 1 2
Mike 1 1
John 1 0
So what it did to count all documents a person edited, is the following
var query = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("ModifiedBy") into rowGroup
select new
{
Name = rowGroup.Key, ModifiedDocuments = rowGroup.Count()
};
This works fine. Now i have to count also the values of the column "Creator". Is this possible and if so, how would i do that? OK, i could iterate over the table, but it would be nice to accomplish this in the LinQ query.
I tried to use "group queryResult by new {}" but i'm not sure if i'm on the right track.
You're best bet would be to just query for created and modified separately and then combine the results with a join.
var modifiedCount = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("ModifiedBy") into rowGroup
select new
{
Name = rowGroup.Key, ModifiedDocuments = rowGroup.Count()
};
var createdCount = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("CreatedBy") into rowGroup
select new
{
Name = rowGroup.Key, CreatedDocuments = rowGroup.Count()
};
var finalResult = from first in modifiedCount
join second in createdCount
on first.Name equal second.Name
select new
{
first.Name,
first.ModifiedDocuments,
second.CreatedDocuments
};
Can't you use the same method with CreatedBy?
var query2 = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("CreatedBy") into rowGroup
select new
{
Name = rowGroup.Key, ModifiedDocuments = rowGroup.Count()
};
And then use your 2 queries sorted by Name.

LINQ: Group by aggregate but still get information from the most recent row?

Let's say I have a table that holds shipping history. I'd like to write a query that counts the amount of shipments per user and gets the shipping name from the most recent entry in the table for that user.
Table structure for simplicity:
ShipmentID
MemberID
ShippingName
ShippingDate
How do I write a LINQ C# query to do this?
It sounds like might want something like:
var query = from shipment in context.ShippingHistory
group shipment by shipment.MemberID into g
select new { Count = g.Count(),
MemberID = g.Key,
MostRecentName = g.OrderByDescending(x => x.ShipmentDate)
.First()
.ShipmentName };
Not really a LINQ answer, but personally, I'd be dropping to SQL for that, to make sure it isn't doing any N+1 etc; for example:
select s1.MemberID, COUNT(1) as [Count],
(select top 1 ShippingName from Shipping s2 where s2.MemberID = s1.MemberID
order by s2.ShippingDate desc) as [LastShippingName]
from Shipping s1
group by s1.MemberID
You can probably do LINQ something like (untested):
var qry = from row in data
group row by row.MemberId into grp
select new {
MemberId = grp.Key,
Count = grp.Count(),
LastShippingName =
grp.OrderByDescending(x => x.ShippingDate).First().ShippingName
};

Categories