LINQ to SQL GroupBy Max() lambda - c#

Please help me convert this to a lambda expression
SELECT [UserID], MAX(Created) Created
FROM [UserHistory]
WHERE userid IN (14287)
GROUP BY [UserID]
Thanks!
EDIT:
Here's what I have so far.
List<T> list; //list is populated
table.Where(x => list.Select(y => y.ClientId).Contains( x.UserID))
.GroupBy(x => x.UserID)
.Select(x => new { x.UserID, x.Created })
.ToList();
When I add the GroupBy, my Select says there's no definition for x.UserID and x.Created.

Here you go:
var userIDs = new[] {14287, };
var results =
dataContext.UserHistories
.Where(user => userIDs.Contains(user.userID))
.GroupBy(user => user.userID)
.Select(
userGroup =>
new
{
UserID = userGroup.Key,
Created = userGroup.Max(user => user.Created),
});

Regarding your edit, as I said in comment, in .Select(x => new { x.UserID, x.Created }), x is no longer a UserHistory, it is IGrouping<int, UserHistory>(1), which does not have UserID and Created properties, but only Key property, which is an user id and implements IEnumerable to enumerate all items for the given key (user id).
Use #DaveShaw snippet as it is the most correct one and most efficient.
(1) I assume UserID is int.

var query = from history in context.UserHistories
where ( new[] {14287} ).Contains(history.userID)
group history by history.UserID into g
select new
{
UserId = g.Key,
MaxCreated = g.Max( x => x.Created)
};

Related

How do I to use Where, Group By, Select and OrderBy at same query linq?

I'm trying to make a linq using where, group by and select at same time but I cannot do it works and it always throws an exception.
How could I do it works ?
Linq
public ActionResult getParceiros(){
//return all partners
IList<ViewParceirosModel> lista = new List<ViewParceirosModel>();
lista = context.usuarios.Where(u => u.perfil == RoleType.Parceiro)
.Select(x => new ViewParceirosModel
{
id = x.id,
nomeParceiro = x.nome,
emailAcesso = x.email
})
.GroupBy(x => x.id)
.OrderBy(x => x.nomeParceiro)
.ToList();
return View(lista);
}
Exception
Your program doesn't do what you want. Alas you forgot to tell you what you want, you only showed us what you didn't want. We'll have to guess.
So you have a sequence of Usarios.
IQueryable<Usario> usarios = ...
I don't need to know what a Usario is, all I need to know is that it has certain properties.
Your first step is throwing away some Usarios using Where: you only want to keep thos usarios that have a Perfil equal to RoleType.Parceirdo:
// keep only the Usarios with the Perfil equal to RoleType.Parceirdo:
var result = usarios.Where(usario => usario.Perfil == RoleType.Parceirdo)
in words: from the sequence of Usarios keep only those Usarios that have a Perfil equal to RoleTyoe.Parceirdo.
The result is a subset of Usarios, it is a sequence of Usarios.
From every Usario in this result, you want to Select some properties and put them into one ViewParceirosModel:
var result = usarios.Where(usario => usario.Perfil == RoleType.Parceirdo)
.Select(usario => new ViewParceirosModel
{
Id = x.id,
NomeParceiro = x.nome,
EmailAcesso = x.email,
})
In words: from every Usario that was kept after your Where, take the Id, the Nome and the Email to make one new ViewParceirosModel.
The result is a sequence of ViewParceirosModels. If you add ToList(), you can assign the result to your variable lists.
However your GroupBy spoils the fun
I don't know what you planned to do, but your GroupBy, changes your sequence of ViewParceirosModels into a sequence of "groups of ViewParceirosModels" Every ViewParceirosModel in one group has the same Id, the value of this Id is in the Key.
So if after the GroupBy you have a group of ViewParceirosModel with a Key == 1, then you know that every ViewParceirosModel in this group will have an Id equal to 1.
Similarly all ViewParceirosModel in the group with Key 17, will have an Id equal to 17.
I think Id is your primary key, so there will only be one element in each group. Group 1 will have the one and only ViewParceirosModel with Id == 1, and Group 17 will have the one and only ViewParceirosModel with Id == 17.
If Id is unique, then GroupBy is useless.
After the GroupBy you want to Order your sequence of ViewParceirosModels in ascending NomeParceiro.
Requirement
I have a sequence of Usarios. I only want to keep those Usarios with a Perfil value equal to RoleType.Parceirdo. From the remaining Usarios, I want to use the values of properties Id / Nome / Email to make ViewParceirosModels. The remaining sequence of ViewParceirosModels should be ordered by NomeParceiro, and the result should be put in a List.
List<ViewParceirosModel> viewParceiroModels = Usarios
.Where(usario => usario.Perfil == RoleType.Parceirdo)
.Select(usario => new ViewParceirosModel
{
Id = x.id,
NomeParceiro = x.nome,
EmailAcesso = x.email,
}
.OrderBy(viewParceirosModel => viewParceirosModel.NomeParceiro)
.ToList();
When you create a LINQ query with group by clause, you receive as result a grouped query.
It is a kind of dictionary that has as key the field you chose to group and as value a list of records of this group.
So, you cannot order by "nomeParceiro" because this field is inside the group.
If you detail how you expect the result I can show you a code example for this.
You can find more details in this section of the doc: https://learn.microsoft.com/pt-br/dotnet/csharp/linq/group-query-results
Let's say ViewParceirosModel look like
public class ViewParceirosModel
{
public int id {get; set;}
public List<string> nomeParceiro {get; set;}
public List<string> emailAcesso {get; set;}
}
After that, you can Groupby then select combine with Orderby like below
IList<ViewParceirosModel> lista = new List<ViewParceirosModel>();
lista = context.usuarios.Where(u => u.perfil == RoleType.Parceiro)
.Select(x => new ViewParceirosModel
{
id = x.id,
nomeParceiro = x.nome,
emailAcesso = x.email
})
.GroupBy(x => x.id)
.Select(g => new ViewParceirosModel
{
id = g.Key,
nomeParceiro = g.Select(p => p.nomeParceiro).OrderBy(x => x.nomeParceiro).ToList()
nomeParceiro = g.Select(p => p.emailAcesso).ToList()
})
.ToList();
You can use the following code.
IList<ViewParceirosModel> lista = new List<ViewParceirosModel>();
lista = context.usuarios.Where(u => u.perfil == RoleType.Parceiro)
.Select(x => new ViewParceirosModel
{
id = x.id,
nomeParceiro = x.nome,
emailAcesso = x.email
})
.OrderBy(x => x.nomeParceiro)
.GroupBy(x => x.id)
.ToList();
or
List<List<ViewParceirosModel>> listb = context.usuarios
.Where(u => u.perfil == RoleType.Parceiro)
.GroupBy(g => g.id).OrderBy(g => g.Key)
.Select(g => g.OrderBy(x => x.nomeParceiro)).ToList();

Using Linq to query Entity Framework with Where clause and many-to-many relation

I have two tables People and Ordersand a many-to-many relationship between the two using PeopleOrders.
Each order is associated with two people: Client and Salesman.
I have the following query:
var query = db.People
.Where(u => u.Description.Equals("Client"))
.Select(u => new {u.Id, OrderId = u.Orders.Select(p => p.Id))
})
.ToList();
This returns a json like this:
[{"Id":1,"OrderId":[2]},{"Id":9,"OrderId":[10,11,12,13]},{"Id":14,"OrderId":[14,15]}]
The ClientID and an array of orders.
I need to invert. Orders can't be an array.
So I need OrderID associated with the ClientID. Something like this:
[{"OrderId":2,"Id":1},{"OrderId":10,"Id":9},{"OrderId":11,"Id":9},{"OrderId":12,"Id":9},{"OrderId":13,"Id":9}]
The query would be something like:
var query = db.Orders
But I need to subquery the People table, so it return only Client; otherwise, it will return a array of People like:
{"OrderId":2,"Id":[1,10]}
Thank you in advance.
Use SelectMany:
var query = db.People
.Where(u => u.Description.Equals("Client"))
.SelectMany(u => u.Orders.Select(p => new {u.Id, p.OrderId}))
.ToList();
You could try something like this (using SelectMany, in order you flatten the projection of your data):
var query = db.People
.Where(person => person.Description.Equals("Client"))
.Select(person => new
{
PersonOrders = person.Orders
.Select(order => new
{
PersonId = person.Id,
OrderId = order.Id))
})
})
.SelectMany(x=>x.PersonOrders)
.ToList();

Selecting some field after using distinct in Linq

I want to use distinct in linq. After i use disctinct i don't select any field. Is it possible to select after distinct.
query.select(x=>x.FirmName).Distinct().Select(x => new InvoiceSumReportrModel { Firma = x.FirmName, Id = x.Id,Country=x.Country }).AsQueryable();
Instead of using Distinct, you can use GroupBy to create a group for each FirmName, then grab the first firm from each group and project it to an InvoiceSumReportModel...
query.GroupBy(x => x.FirmName,
(k, g) => g.Select(
x => new InvoiceSumReportrModel
{
Firma = x.FirmName,
Id = x.Id,
Country = x.Country
})
.First());

Linq to Entities group query giving list of results in each group

If I have a set of entities with 3 properties (Id, Type, Size) all of which are strings.
Is there a way using Linq to Entities where I can do a group query which gives me the Size + Type as the key and then a list of the related Id's for that Size + Type?
Example below of getting the count:
Items.GroupBy(x => new { x.Size, x.Type})
.Select(x => new { Key = x.Key, Count = x.Count() })
but I am looking to get a list of the Ids for each grouping?
I am looking to see if it is possible using Linq-to-EF before I decide to iterate through this in code and build up the result instead.
If you want to get List of Ids for each group then you have to select x.Select(r => r.Id) like:
var result = Items.GroupBy(x => new { x.Size, x.Type })
.Select(x => new
{
Key = x.Key,
Ids = x.Select(r => r.Id)
});
Another way to build up a Dictionary<string, IEnumerable<string?>> in dotnet 6.0 according to the docs;
where we have the dictionary Key as {Size, Type} and Value the list of Ids, you can write:
Dictionary<string, IEnumerable<string?>> result = Items.GroupBy(item => new { item.Size, item.Type }
item => item.Id),
(itemKey, itemIds) =>
{
Key = itemKey,
Ids = itemIds
})
.ToDictionary(x => x.Key, x=> x.Ids);

How to select multiple column and distinct one column by LINQ?

I have:
var names = db.tblPosts.Select(x => new { x.UserID, x.title }).Distinct().ToList();
I want select UserID and title and UserID is distinct.
but not worked and userID is not distinct..
var items = db.tblPosts
.GroupBy(x => x.UserId)
.Select(g => new { UserId = g.Key, Title = g.FirstOrDefault().Title })
.ToList();
It will return first Title for each UserId. Add additional OrderBy/ThenBy to sort items within group before taking first one.

Categories

Resources