EntityFramework - Group by unordered pair in LINQ query - c#

I have a table that contains 4 columns **(User_from, User_to,Message,Date)**
I need to get the last message a user have in all participant chats.
var all = from m in db.Peers
where m.User_Id_To == id || m.User_Id_From == id
group m by new { m.User_Id_To, m.User_Id_From } into g
select g.OrderByDescending(x => x.Date).FirstOrDefault();
The code above works to get the last message for each id,
but still having an issue.
Consider having this 2 records below :
User_from User_To Content Date
1 2 hi 01-01-2018
2 1 wlc 02-02-2018
When I am trying to use my query I am getting both records. I just need the last one according to date.

In GroupBy you can create a conditional key so when you want to group by a pair of values where order dosen't matter you can construct key as an anonymous type with the first property set to min value and the second to max value.
var all = from m in db.Peers
where m.User_Id_To == id || m.User_Id_From == id
group m by new
{
Min = m.User_Id_To < m.User_Id_From ? m.User_Id_To : m.User_Id_From,
Max = m.User_Id_To > m.User_Id_From ? m.User_Id_To : m.User_Id_From
}
into g
select g.OrderByDescending(x => x.Date).FirstOrDefault();

Related

Retrieving data from sql to datagridview using LinqToSql

I have a datatable in sql and a datagridview in winform. datatable holds measurement results from a mould with a MouldID. For every measurement 50 lines of results are logged to table. To track measurement count for same mould, i also have MeasId column which incremented by 1 for every measurement input. Please see picture for table view.
What i need to do, retrieve only the rows with choosen MouldID (from a combobox) with last MeasID.
I tried following codes but i couldn't figure out how to group this rows with MeasId.
using (LinqDataClassesDataContext dataContext = new
LinqDataClassesDataContext())
{
// attemp 1
var query=dataContext.SupplierVals
.Where(m=>m.MouldID==comboBMouldID.SelectedValue.ToString())
.OrderByDescending(m => m.MeasId).FirstOrDefault();
// attemp 2
var query=dataContext.SupplierVals
.Where(mr=>mr.MouldID==comboBMouldID.SelectedValue.ToString())
.OrderByDescending(mr => mr.MeasId).Select();
// attemp 3
var query = (from x in dataContext.SupplierVals
where x.MouldID == comboBMouldID.SelectedValue.ToString()
select x).First();
// attemp 4
var query = from x in dataContext.SupplierVals
where x.MouldID == comboBMouldID.SelectedValue.ToString()
group x by x.MeasId into grp
select grp.OrderByDescending(x => x.MeasId).First();
daGridUnused.AutoGenerateColumns = false;
daGridUnused.Columns["unusedShowDist"].DataPropertyName = "Distnc";
daGridUnused.Columns["unusedShowAper"].DataPropertyName = "Apert";
daGridUnused.Columns["unusedShowTap"].DataPropertyName = "Taper";
daGridUnused.DataSource = query;
}
None of these queries return what i need from datatable.
What am i doing wrong?
It seems that you were almost there. You simply need to filter also by the Max value and order by the ValueId:
string mouldId = comboBMouldID.SelectedValue.ToString();
int max = dataContext.SupplierVals
.Where(m=>m.MouldID == mouldId)
.Max(m => m.MeasId);
var query=dataContext.SupplierVals
.Where(m=>m.MouldID == mouldId && m.MeasId == max).ToList();
disclaimer: this query can surely be optimized, I am working on a better solution

convert rows to column in entity framwork

how can i convert rows to column in entity framework!?
i have a result like this:
and i want this result:
my entity code i this :
(from loanPerson in context.LoanPersons.AsParallel()
join warranter in context.Warranters.AsParallel() on loanPerson.Id equals warranter.LoanPersonId
where loanPerson.Id == 84829
select new
{
loanPersonId = loanPerson.Id,
waranterId = warranter.WarranterPersonID,
}).ToList();
and number of the row always less than 3 and i want to have 3 column.
please let me know your answer.
tanks.
This query will return the only one row, where waranterIds will contain, at this particular case, three WarranterPersonID values, also this field is of List<int> type, because it's quantity not known at compile time:
var answer = (from loanPerson in context.LoanPersons.Where(x => x.Id == 84829)
join warranter in context.Warranters
on loanPerson.Id equals warranter.LoanPersonId
group warranter by loanPerson.Id into sub
select new
{
loanPersonId = sub.Key,
waranterIds = sub.Select(x => x.LoanPersonId).ToList()
//if you sure, that quantity equals 3,
//you can write this code instead of waranterIds:
//zamen1 = sub.Select(x => x.LoanPersonId).First(),
//zamen2 = sub.Select(x => x.LoanPersonId).Skip(1).First(),
//zamen3 = sub.Select(x => x.LoanPersonId).Skip(2).First()
}).ToList();

How to use Linq query Result in OrderBy?

Here i had scenario to get the data in date wise of this month(Present month)
Excepted Result
Date_time sum(collection.amountreceived ) Sum(bank_deposit.depositamount)
1/07/2014 2000 1000
2/07/2014 3000 3000
Schema
bank_deposit
agentid (nvarchar(30))
depositamount (DECIMAL(10,0))
date_time (TIMESTAMP)
collection
customeridn (varchar(30))
amountreceived (DECIMAL(10,0))
date_time (TIMESTAMP)
agentid (nvarchar(30))
Here I used union to get the datetime column data in one column
var unionDateColumn = ((from agent in db.collections select agent.Date_Time)
.Union(from u in db.bank_deposit select u.Date_Time)).ToList();
How can i use this unionDateColumn data for orderby and to get expected output?
Below is query for sum of amount but here my issue is how to
var model = (from coll in db.collections.Where(e => e.AgentID == item.AgentID)
let depositedAmount = db.bank_deposit.Where(d => d.AgentID == item.AgentID ).Sum(c => c.DepositedAmount) == null ? 0
: db.bank_deposit.Where(d => d.AgentID == item.AgentID).Sum(x => x.DepositedAmount)
let collectionAmount = db.collections.Where(c => c.AgentID == item.AgentID).Sum(c => c.AmountReceived) == null ? 0
: db.collections.Where(v => v.AgentID == item.AgentID).Sum(m => m.AmountReceived)
select new GetBalanceAmount
{
DepositedAmount = depositedAmount,
CollectionAmount = collectionAmount
});
I assume you want to order the result by date_time
var result = unoinDateColumn.OrderBy(t=>t.Date_Time).ToList().;
Why FirstOrDefault ? i asume you want every row.
Sajeetharan's example:
var result = unoinDateColumn.OrderBy(t=>t.Date_Time).ToList();
result is the same as "select * from unionDateColumn order by DateTime"
Your example:
model.ToList().OrderByDescending(unoinDateColumn).FirstOrDefault();
is the same as "Select * from model orderby unionDateColumn"
May i ask why you are handling each column seperately? insted of in one large array ?
Handle it in one array, and do like this model.OrderByDescending(x => x.Date_Time);
it will affect the object model and order it like this model = model.sortedBy(model.Date_Time);

LINQ How to Show Average of all results in GroupBy

I am trying to write a query which returns the average time spent on a job in a ticketing system.
There are multiple time logs in each job so I need to group by the SO Number and then somehow get an average of all of the results.
The current query returns a list of every service order and the total minutes spent to the job.
How do I make this show me the average minutes spent on each job?
from so in TblServiceOrders
from sologs in TblSOLogs.Where(x => x.SONumber == so.SONumber).DefaultIfEmpty()
where so.DateClosed >= new DateTime(2013,07,01)
where so.DateClosed <= new DateTime(2013,07,02)
where sologs.ElapsedHours != 0 || sologs.ElapsedMinutes != 0
group new { sologs.ElapsedHours, sologs.ElapsedMinutes } by so into g
select new {
g.Key.SONumber,
elapsed = g.Average (x => (x.ElapsedHours == null ? 0 : x.ElapsedHours * 60) + (x.ElapsedMinutes == null ? 0 : x.ElapsedMinutes))
}
==EDIT==
This looks like it is getting close but it is giving me an average of every time log and not an average of the total time logs in each SO.
Please help?
from so in TblServiceOrders
join sologs in TblSOLogs on so.SONumber equals sologs.SONumber
where so.DateClosed >= new DateTime(2013,07,01)
where so.DateClosed <= new DateTime(2013,07,03)
where sologs.ElapsedHours != 0 || sologs.ElapsedMinutes != 0
group sologs.SONumber by sologs into g
group new {g.Key.ElapsedHours, g.Key.ElapsedMinutes} by "Total" into t
select t.Average (x => (x.ElapsedHours == null ? 0 : x.ElapsedHours * 60) + (x.ElapsedMinutes == null ? 0 : x.ElapsedMinutes))
I've worked it out for the most part, Hopefully this can help others.
The first part of my question was getting all the results into the same group without a distinct value to Group By. This was achieved by declaring a string in the Group By such as "Total".
For Example:
group tblName.FieldName by "Example" into group1
For the second part I needed to perform a Group By on the Sum of another Group By. Below is an example of declaring two new values generated from the Sum of a Group By:
group new { tblName.FieldName1, tblName.FieldName2} by tblName into group1
group new { SumField1 = g.Sum (x => x.FieldName1), SumField2 = g.Sum (x => x.FieldName2) } by "Totals" into newgroup2
Here is a full example of the code I ended up writing, It works well in LINQPad but I am still working on implementation into a Visual Studio C# DataGridView.
from so in TblServiceOrders
join sologs in TblSOLogs on so.SONumber equals sologs.SONumber
where so.DateClosed >= new DateTime(2014,01,17)
where so.DateClosed <= new DateTime(2014,01,17)
where sologs.ElapsedHours != 0 || sologs.ElapsedMinutes != 0
group new {sologs.ElapsedHours, sologs.ElapsedMinutes} by sologs.SONumber into g
group new {hours = g.Sum (x => x.ElapsedHours), mins = g.Sum (x => x.ElapsedMinutes)} by "Totals" into t
select new {
Average = t.Average (x => (x.hours * 60) + x.mins),
Count = t.Count ()
}

linq-to-sql grouping anonymous type

I have a table the contains appointments. These appointments have different statuses (byte from 1 to 5) and dates; the column for the date is simply called AppointDate. I pass in a list of IDs and I want to group the result based on the status AND whether the date of the appointment is past or not.
TheIDs is a list of longs that's passed in as the parameter. This is what I have so far:
var TheCounterInDB = (from a in MyDC.Appointments
where TheIDs.Contains(a.ID)
group a by a.AppointStatus into TheGroups
select new {
TheStatus = TheGroups.Key,
TheTotalCount = TheGroups.Count(),
TheLateCount = ?,
ThePendingCount = ?
}).ToList();
Basically, I want TheLateCount to be the count of all the appointments where status is 1 AND the date is past and ThePendingCount to be the count where status is 1 AND the date is not past. My anonymous type is good to return the count of all the different statuses (that's where the .Key is) but I'm wondering how to best add the date requirement into the grouping.
Thanks for your suggestions.
var TheCounterInDB = (from a in MyDC.Appointments
where TheIDs.Contains(a.ID)
group a by a.AppointStatus into TheGroups
select new {
TheStatus = TheGroups.Key,
TheTotalCount = TheGroups.Count(),
TheLateCount = TheGroups.Count(x => x.AppointStatus == 1 && x.AppointDate < DateTime.Today),
ThePendingCount = TheGroups.Count(x => x.AppointStatus == 1 && x.AppointDate >= DateTime.Today)
}).ToList();

Categories