LINQ Groupby query on a single column - c#

I have a situation where I have a Job which has multiple tests which run at specific intervals. A job run generates a unique TestRunId which is a GUID, which is used to reference multiple results, basically grouping a particular run with a unique RunId(GUID).
Now the problem is that I need to select unique runs which have been generated, but my LINQ query picks up every run.
I tried something like this
var testRunIds = ((from tests in context.testresults
where tests.JobId == jobId
select new
{
tests.TestRunId
}).GroupBy(t=>t.TestRunId).OrderBy(t=>t.Key).Skip((pagenum - 1) * pagesize).Take(pagesize)).ToList();
But as I said, this query picks up each and every testResult. Not sure how I do this now. I tried Distinct(), but that too didnt work. Sample data below.
Thanks
I believe the problem is that I have multiple TestRunId values as its essentially a grouping. Inorder to achieve what I need, I tried using (got using Linqer)
from Queries in db.TestResult
where
Queries.JobId == 1
group Queries by new {
Queries.TestRunId,
Queries.StartTime,
Queries.EndTime
} into g
orderby
g.Key.TestRunId
select new {
_ID = (int?)g.Max(p => p.Id),
g.Key.TestRunId,
g.Key.StartTime,
g.Key.EndTime
}
But this works only for MSSQL datasource which is essentially a
SELECT max(id)[ ID],
TestRunId,
StartTime,
Endtime
FROM dbo.query where jobid = 1 group by TestRunId,StartTime,Endtime order by StartTime;
But what I need is
SELECT TestRunId,StartTime,Endtime FROM testresult where jobid = 1 group by TestRunId order by StartTime;
for MySQL.

Try this:-
var jobs = context.testresults;
var query2 = jobs.Where(x => x.TestID == 1).OrderBy(x => x.StartTime).Select(x => x.TestRunID).Distinct();
Working Fiddle.

I think you're possibly looking for this:
var testRunIds = context.testresults.Where(t => t.JobId == jobId).OrderBy(t => t.starttime)
.Select(t => t.TestRunId).Distinct().Skip((pagenum - 1) * pagesize).Take(pagesize)
.ToList();
Do the filtering and ordering first, then select the single field needed, then use Distinct() for uniqueness, then skip/take as required. Selecting the single field first then attempting to order or filter on other fields in the table won't work as those fields are no longer part of the query.

Thanks for helping me out. I managed to do this in a two step process.
var testRunIds = (from tests in context.testresults
where tests.JobId == jobId
select new
{
tests.TestRunId,
tests.StartTime
}).OrderBy(x => x.StartTime).Skip((pagenum - 1) * pagesize).Take(pagesize).GroupBy(x=>x.TestRunId).ToList();
var resultData = testRunIds.Select(testRunId => (context.testresults.Where(
items => items.TestRunId == testRunId.Key)).FirstOrDefault()).ToList();

Related

Read most recently inserted rows by Date using linq to Entity framework

I have a log table in my db and wants to fetch only those records which are added most recently based on the column name RowCreateDate, this is how I am trying to achieve the records which is bringing the rows from the db but I feel may be there is a better way to achieve the same.
using (var context = new DbEntities())
{
// get date
var latestDate = context.Logs.Max(o => o.RowCreateDate);
if(latestDate!=null)
{
lastDate = new DateTime(latestDate.Value.Year, latestDate.Value.Month, latestDate.Value.Day,00,00,00);
logs = context.Logs.Where( o.RowCreateDate >= lastDate).ToList();
}
}
What i need to know I am doing right or there would another better way?
Yet another option:
context.Logs.Where(c => DbFunctions.TruncateTime(c.RowCreateDate) == DbFunctions.TruncateTime(context.Logs.Max(o => o.RowCreateDate)))
This reads explicitly like what you want (get all rows with date equals max date) and will also result in one query (not two as you might have expected).
You can't simplify this code because LINQ to Entities does not support TakeWhile method.
You can use
using (var context = new DbEntities())
{
// get date
var latestDate = context.Logs.Max(o => o.RowCreateDate);
if(latestDate!=null)
{
lastDate = new DateTime(latestDate.Value.Year, latestDate.Value.Month, latestDate.Value.Day,00,00,00);
logs = context.Logs
.OrderBy(o => o.RowCreateDate)
.AsEnumerable()
.TakeWhile(o => o.RowCreateDate >= lastDate);
}
}
BUT it takes all your data from DB, which is not very good and I do not recommend it.
I think this will do (if we assume you want to get top 3 most recent record):
var topDates = context.Logs.OrderByDescending(x=>x.RowCreateDate).Take(3)
First, I think that your code is fine. I don't see the problem with the two queries. But if you want to simplify it you use TruncateTime, like this:
IGrouping<DateTime?, Logs> log =
context.Logs.GroupBy(x => DbFunctions.TruncateTime(x.RowCreateDate))
.OrderByDescending(x => x.Key).FirstOrDefault();
It will return a grouped result with the logs created during the last day for RowCreateDate.

How to get invoice ID of settled Executions

Lets say i have table with the Name Executions like this :
InvoiceID------ExecutionID-------IsSettled
123-----1-----0
123-----2-----1
345-----3-----1
345-----4-----1
567-----5-----0
567-----6-----0
My Question :
What is the query that retrieves only InvoiceIDs where all it's Executions have IsSettled=1.?
I mean the result of the query should be like this:
345-----3-----1
345-----4-----1
i want to execulde any invoices that has any executions with isSettled flog=0,in my question u will find tha invocieID=123 has 2 executions ,one with IsSettled flag=0 and another Execution with Issettled flag=1, so i dont want to include this invoice in my result set as it has one execution with isSettled flag =0
If anyone knows also if I have an Execution Object how can i get the same result using Linq.
The query can be either SQL or LINQ
Thanks
Make a list of invoices Id's that are not settled:
var notNeeded = ExecutionObject.Where(e => e.IsSettled == 0).Select(s => s.InvoiceId).ToList();
Then filter on the invoices that are settled and ensure the invoice id is in the not settled list.
var invoices = ExecutionObject.Where(e => e.IsSettled == 1 && !notNeeded.Contains(e.InvoiceId)).ToList();
The query can be either SQL or LINQ
Query
select * from Executions
where InvoiceID in
(
select InvoiceID from Executions
group by InvoiceID
having min(Issettled)=1
)
SQL FIDDLE
Consider this:
var invoices = (from execution in ExecutionObject
where execution.IsSettled == 1
&& !ExecutionObject.Where(x=>x.IsSettled == 0).Select(y=>y.InvoiceID).Contains(execution.InvoiceID)
select execution.InvoiceID).Distinct().ToList();
I haven't tested it, but the idea is that you filter first by IsSettled == 1 and then remove any that have a record where IsSettled == 0.
It'd be something as simple as the following in linq:
Executions.Where(e => e.IsSettled == 1)
After understanding the question and giving it a go in LinqPad the following Linq query will get what you need:
Executions.GroupBy(e => e.InvoiceId)
.Where(g => g.All(e => e.IsSettled == true))
.SelectMany(g => g)
The linq script is avaliable here: http://share.linqpad.net/fawl6l.linq
If this is a linq query (you haven't told us) then you could use: -
var settled = executions.GroupBy(id => id.invoiceid).Where(inv => inv.All(s => s.issettled)).Select(x => x).ToList();
I think the key point here is you want invoices where there is not a settled = 0?
select distinct InvoiceID
from executions
where invoiceID <> ALL(select invoice_id from executions where is_settled = 0)
or in linq
var q = from i in ctx.Invoices
where ctx.Invoices.All(x => is_settled == 1 || x.invoice_id != i.invoice_id)
select i.invoice_id;
var result = q.Distinct();

wpf and ef select part of a table with include

I have a table with many fields and I want to get only a few individual fields, I work with EF and I add another table to the query as follows
var Test= ve.Folders.Include("Hosting")
.Where(a => a.Collateral!= true)
.AsEnumerable()
.Select(p => new
{
id = p.Folder_Id,
name = p.Full_Name,
add = p.Address,
date1 = p.Collateral_Date,
sName = p.Hosting._Name
})
.ToArray();
But with the field (sName= p.Hosting._Name) that is associated with the second table without any value query not working
Many attempts have been tried but without result (interesting when I ask without Select everything works well)
Thanks in advance for any help
One thing to note is that, in this case, there's little benefit to the Select after the call to AsEnumerable, since all the data in the table is still queried from the database (not just the fields you specifiy).
If you want to avoid that, and only query those five fields, you can remove the AsEnumerable call. That means the Select will execute as part of the SQL query. This also means the Include is unnecessary, since the Select will query all of the data you want.
var Test= ve.Folders
.Where(a => a.Collateral!= true)
.Select(p => new
{
id = p.Folder_Id,
name = p.Full_Name,
add = p.Address,
date1 = p.Collateral_Date,
sName = p.Hosting._Name
})
.ToArray();

How to write an linq statement to get the last of a group of records

I have 2 SQL statements that basically do the same thing, that is, retrieve the last record from a table based on a datetime field for a group of records. I am using the data-first Entity Framework model. How would I write either of these SQL statements using LINQ Lambda functions?
ie,
var u = db.AccessCodeUsage.Where(...).GroupBy(...)
rather than
var u = from a in db.AccessCodeUsage
where ...
group by ...
SQL Statements:
SELECT *
FROM AccessCodeUsage a
WHERE NOT EXISTS (SELECT 1
FROM AccessCodeUsage
WHERE LocationId = a.LocationId
AND Timestamp > a.Timestamp)
SELECT a.*
FROM AccessCodeUsage a
WHERE a.Timestamp =
(SELECT MAX(Timestamp)
FROM AccessCodeUsage
WHERE a.LocationId = LocationId
AND a.AccessCode = AccessCode
GROUP By LocationId, AccessCode)
If you need to have the method-call form, but are finding it tricky to work out, then use the other syntax first:
from a in db.AccessCodeUsage
orderby a.TimeStamp descending
group a by a.LocationId into grp
from g in grp select g.First();
Then convert to method calls by taking each clause one at a time:
db.AccessCodeUsage
.OrderByDescending(a => a.TimeStamp)
.GroupBy(a => a.LocationId)
.Select(g => g.First());
From which I can workout the second without bothering to write out the linq-syntax form first:
db.AccessCodeUsage
.OrderByDescending(a => a.TimeStamp)
.GroupBy(a => new {a.LocationId, a.AccessCode})
.Select(g => g.First());
(Except it doesn't include what may be a bug, in that if timestamps aren't guaranteed unique, the SQL given in the question could include some extra inappropriate results).
I can't check on the SQL produced right now, but it should hopefully be equivalent in results (if not necessarily matching). There's cases where grouping doesn't translate to SQL well, but I certainly don't think this would be one.
I ended up using the following which corresponds to the first SQL statement.
// Retrieve only the latest (greatest value in timestamp field) record for each Access Code
var last = AccessCodeUsages.Where(u1 => !AccessCodeUsages
.Any(u2 => u2.LocationId == u1.LocationId &&
u2.AccessCode == u1.AccessCode &&
u2.Timestamp > u1.Timestamp));

Can I clone an IQueryable in linq? For UNION purposes?

I have a table of WorkOrders. The table has a PrimaryWorker & PrimaryPay field. It also has a SecondaryWorker & SecondaryPay field (which can be null).
I wish to run 2 very similar queries & union them so that it will return a Worker Field & Pay field. So if a single WorkOrder record had both the PrimaryWorker and SecondaryWorker field populated I would get 2 records back.
The "where clause" part of these 2 queries is very similar and long to construct. Here's a dummy example
var q = ctx.WorkOrder.Where(w => w.WorkDate >= StartDt && w.WorkDate <= EndDt);
if(showApprovedOnly)
{
q = q.Where(w => w.IsApproved);
}
//...more filters applied
Now I also have a search flag called hideZeroPay. If that's true I don't want to include the record if the worker was payed $0. But obviously for 1 query I need to compare the PrimaryPay field and in the other I need to compare the SecondaryPay field.
So I'm wondering how to do this.
Can I clone my base query q and make a primary & secondary worker query out of it and then union those 2 queries together?
Hmm, I'm not sure that I understand you intention. But I think cloning is not neccessary. Why don't you split two new queries from your base query?
var baseQuery = ctx.WorkOrder.Where(w => w.WorkDate >= StartDt && w.WorkDate <= EndDt);
IQueryable<WorkOrder> query1;
if (showApprovedOnly)
{
query1 = baseQuery.Where(w => w.IsApproved);
}
//more filters on query1
...
IQueryable<WorkOrder> query2;
if (/*something*/)
query2 = baseQuery.Where(w => w.SomeThing);
After defining your queries you can interpret them (per enumeration) and retrieve your different results.
var res1 = query1.ToList();
var res2 = query2.ToList();
When you do your second Where you are actually cloning your query.
Here you create your initial queryable object.
var q = ctx.WorkOrder.Where(w => w.WorkDate >= StartDt && w.WorkDate <= EndDt);
Here you create a new queryable with the where associated
if(showApprovedOnly)
{
q = q.Where(w => w.IsApproved);
}
//...more filters applied
All you need to do is create a new variable to store the ammended query.
var qw = q.Where(w=> w.IsApproved);
This works because the queryable is created as an object and the query itself is only run once you enumerate it.

Categories

Resources