Entity Framework - GroupBy then OrderBy - c#

I have a group of records that includes PatientID and Appointment Date.
I would like to group them by PatientID and order the groups by the oldest appointment in each PatientID group. Like this...
ID ApptDate
----------------------
3 2/5/2005 (oldest compared to all groups , so group "ID = 3" is sorted first)
3 5/10/2006
3 6/2/2010
1 8/5/2007
1 9/1/2015
2 6/15/2009
2 9/19/2009
I'm pretty sure I need to use grouping first to obtain the oldest date value for each ID and then order by that value but I am stuck understanding how the two functions will work together.
var query = from a in db.Appointments
group a by new { a.Id, a.ApptDate} into pa
select new {
ID = pa.Key.Id,
Date = pa.Min(x =>x.ApptDate) ...
... but I crash and burn at this point.
Any help appreciated.

I modified a bit Tanveer Badar's answer to return a row for each entity.
Create a class for your return data
public class ReturnType
{
public int ID { get; set; }
public DateTime AppDate { get; set; }
}
Get a group of IDs and enumerable of ordered dates
var result = db.Appointment
.GroupBy(a => a.Id)
.OrderBy(a => a.Min(n => n.Date))
.Select(a => new { ID = a.Key, AppDates = a.OrderBy(na =>
na.Date).Select(ne => ne.Date) })
.ToList();
Then flatten the returned list. I tried with SelectMany but with no success.
var results = new List<ReturnType>();
foreach (var a in result)
{
foreach (var date in a.AppDates)
{
var returnType = new ReturnType
{
ID = a.ID,
AppDate = date
};
results.Add(returnType);
}
}

You requirements are as follows (though the question does not mention one of them, but it is apparent from how data is laid out):
Group based on patient ID.
Sort groups based on oldest appointment date in each group.
Sort data within a group based on appointment date.
var query = records.GroupBy(r => r.PatientId) // Group patients
.OrderBy(g => g.Min(r => r.AppointmentDate)) // sort groups by oldest record in each
.Select(g =>
new
{
PatientId = g.Key,
Records = g.OrderBy(r => r.AppointmentDate) // sort records within a group by oldest
});

In my case it works fine...
var query = from a in db.Appointments
group a by new { a.Id, a.ApptDate} into pa
select new {
ID = pa.Key.Id,
Date = pa.Max(x =>x.ApptDate)
}).Select(x=>new {
x.ID,x.Date
}).ToList();

db.Appointments.GroupBy(new {ID = item.ID, ApptDate = item.ApptDate}).OrderByDescending(item => item.ApptDate)

Related

How can I get the best seller by product group using LINQ

I need to retrieve the name, product type and sum of the seller with the highest sales in each product type using linq and return the list to a view.
{
public ActionResult Query2()
{
// this part gets me everything into one model type
List<QueryViewModel> result = db.SaleProducts
.GroupBy(prod => prod.Type)
.SelectMany(sale => sale.Select(
row => new QueryViewModel
{
Seller = row.Sale.User.Name,
ProductType = row.Type,
Sales = (double)sale.Where(x => x.Sale.UserId == row.Sale.UserId && x.Type.Equals(row.Type)).Sum(price => price.Price)
}
)).Distinct().ToList<QueryViewModel>();
// this gives me the best per product type but i cant get the seller name
List<QueryViewModel> filter = (from res in result
group res by res.ProductType into prodGroup
select new QueryViewModel
{
ProductType = prodGroup.Key,
Sales = prodGroup.Max(x => x.Sales)
}).ToList<QueryViewModel>();
// this is really just to get the seller name at this point
List<QueryViewModel> something = (from res in result
join f in filter on res.Sales equals f.Sales
select new QueryViewModel
{
Seller = res.Seller,
ProductType = res.ProductType,
Sales = res.Sales
}).ToList<QueryViewModel>();
return View(something);
}
}
It should return a list of QueryViewModel(name, product type, total sales).
It does return that, but this seems horribly messy and I'm not understanding LINQ enough to clear this up.
Is there a better cleaner way to achieve my desired output?
The first grouping should be by type and Seller.
Something like this should get you going:
Quote_Masters.GroupBy(qm => new { qm.OrderTypeId, qm.SalesRepEmployeeId })
.Select(x => new { Name = x.Key.SalesRepEmployeeId, x.Key.OrderTypeId, Total = x.Sum(qm => qm.Total_Price) })
.OrderByDescending(x => x.Total).GroupBy(x => x.OrderTypeId).Select(x => x.FirstOrDefault())
Just change out your appropriate tables and fields.
Edit: Your select to QueryViewModel would be the new {Name = x.Key.SalesRepEmployeeId, x.Key.OrderTypeId, Total = x.Sum(qm => qm.Total_Price)}

Orderby Not working after grouping items

I have a function that's main goal to group items by id, count them and finally order them by count.
var Db = list.Select(x => new
{
Id = x
});
var groups = Db.GroupBy(g => new { Id = g.Id })
.Select(g => new
{
Id = g.Key.Id,
Cnt = g.Count()
}).Distinct().OrderBy(g => g.Cnt).ToList();
Do you have any idea, where the error might be? It is not ordering. I have a bunch of low counts at first then it becomes random.
'list' is a one-dimensional list with many duplicated Ids (string) .
This is the output its giving out: ( I do not understand why there's duplicates in the ID since I'm only grouping by one key).
Link to output : https://pastebin.com/NjqJ4Aub

Group By Query with Entity Framework

In my application I have Movements associated with a category.
I want a list of the most frequent category.
My objects are:
Category: catId, catName
Movement: Movid, movDate, movMount, catId
I think it would have to raise it with a "Group By" query (grouping by catId and getting those more)
(Im using Entity Framework 6 in c#)
From already thank you very much!
IMPORTANT: Entity Framework 7 (now renamed to Entity Framework Core 1.0) does not yet support GroupBy() for translation to GROUP BY in generated SQL. Any grouping logic will run on the client side, which could cause a lot of data to be loaded.
https://blogs.msdn.microsoft.com/dotnet/2016/05/16/announcing-entity-framework-core-rc2
group the movements by category and select catid and count.
join this result with category to get the name and then descending sort the results on count.
var groupedCategories = context.Movements.GroupBy(m=>m.catId).Select(g=>new {CatId = g.Key, Count = g.Count()});
var frequentCategories = groupedCategories.Join(context.Categories, g => g.CatId, c => c.catId, (g,c) => new { catId = c.catId, catName = c.catName, count = g.Count }).OrderByDescending(r => r.Count);
foreach (var category in frequentCategories)
{
// category.catId, category.catName and category.Count
}
i hope this help:
var query = dbContext.Category.Select(u => new
{
Cat = u,
MovementCount = u.Movement.Count()
})
.ToList()
.OrderByDescending(u => u.MovementCount)
.Select(u => u.Cat)
.ToList();
I resolved the problem!
I used the proposal by "Raja" solution (Thanks a lot!).
This return a collection composed of "Category" and "Count". I Change it a bit to return a list of Categories.
var groupedCategories = model.Movement.GroupBy(m => m.catId).Select(
g => new {catId= g.Key, Count = g.Count() });
var freqCategories= groupedCategories.Join(model.Category,
g => g.catId,
c => c.catId,
(g, c) => new {category = c, count = g.Count}).OrderByDescending(ca => ca.count).Select(fc => fc.category).ToList ();
you just need to use navigation property on category simply, you have a navigation property on category contains all related Movement, i call it Movements in following query. you can write your query like this, with minimum of connection with DB.
class Cat
{
public Guid catId { get; set; }
public string catName { get; set; }
public IEnumerable<Movement> Movements { get; set; }
public int MovementsCount { get { return Movements.Count(); } }
}
var Categories = category.Select(u => new Cat()
{
u.catId,
u.catName,
Movements = u.Movements.AsEnumerable()
}).ToList();
var CategoriesIncludeCount = Categories.OrderBy(u => u.MovementsCount).ToList();

Use Linq to return first result for each category

I have a class (ApplicationHistory) with 3 properties:
ApplicantId, ProviderId, ApplicationDate
I return the data from the database into a list, however this contains duplicate ApplicantId/ProviderId keys.
I want to supress the list so that the list only contains the the earliest Application Date for each ApplicantId/ProviderId.
The example below is where I'm currently at, but I'm not sure how to ensure the earliest date is returned.
var supressed = history
.GroupBy(x => new
{
ApplicantId = x.ApplicantId,
ProviderId = x.ProviderId
})
.First();
All advice appreciated.
Recall that each group formed by the GroupBy call is an IGrouping<ApplicationHistory>, which implements IEnumerable<ApplicationHistory>. Read more about IGrouping here. You can order those and pick the first one:
var oldestPerGroup = history
.GroupBy(x => new
{
ApplicantId = x.ApplicantId,
ProviderId = x.ProviderId
})
.Select(g => g.OrderBy(x => x.ApplicationDate).FirstOrDefault());
You are selecting first group. Instead select first item from each group:
var supressed = history
.GroupBy(x => new {
ApplicantId = x.ApplicantId,
ProviderId = x.ProviderId
})
.Select(g => g.OrderBy(x => x.ApplicationDate).First());
Or query syntax (btw you don't need to specify names for anonymous object properties in this case):
var supressed = from h in history
group h by new {
h.ApplicantId,
h.ProviderId
} into g
select g.OrderBy(x => x.ApplicationDate).First();

Ordering collection within group partitions using LINQ

I have simple type Question:
public class Question
{
public string[] Tags { get; set; }
public DateTime Created { get; set; }
}
While I have a list of questions, I need to filter them along list of tags (called filters). The questions which have the most tags matched by the filters list, should be placed higher in the result collection. I wrote expression for that:
public IList<Question> GetSimiliar(IList<Questions> all, string[] filters)
{
var questions = all.Select(
x => new
{
MatchedTags = x.Tags
.Count(tag => filters.Contains(tag)),
Question = x
})
.Where(x => x.MatchedTags > 0)
.OrderByDescending(x => x.MatchedTags)
.Select(x => x.Question);
return questions.ToList();
}
Now I need a support for such situation, where I have more than one question with the same quantity of matched tags. Such questions should be further sorted by creation date (from newest to oldest).
Example of what I want:
filter: tags = [a,b,c]
collection of questions to be filtered:
q1 { tags = [a], created = 1939 }
q2 { tags = [b], created = 1945 }
q3 { tags = [a,b,c], created = 1800 }
q4 { tags = [a,b], created = 2012 }
q5 { tags = [z], created = 1999 }
result - the sorted collection:
q3
q4
q2
q1
How to do that using linq ?
Now I need a support for such situation, where I have more than one question with the same quantity of matched tags. Such questions should be further sorted by creation date (from newest to oldest).
Use ThenBy or ThenByDescending to further sort your query. Use these methods to break ties in prior ordering.
.OrderByDescending(x => x.MatchedTags)
.ThenByDescending(x => x.Question.Created)
.Select(x => x.Question);
The 101 Linq Samples page has a nested grouping example. This sample uses group by to partition a list of each customer's orders, first by year, and then by month:
public void Linq43()
{
List<Customer> customers = GetCustomerList();
var customerOrderGroups =
from c in customers
select
new
{
c.CompanyName,
YearGroups =
from o in c.Orders
group o by o.OrderDate.Year into yg
select
new
{
Year = yg.Key,
MonthGroups =
from o in yg
group o by o.OrderDate.Month into mg
select new { Month = mg.Key, Orders = mg }
}
};
ObjectDumper.Write(customerOrderGroups, 3);
}

Categories