Reputation: 2498
I've been toying with this for a while and just can't get it. I'm new to Linq, C# and these Lambda things.
What I want to do is group entities according to two properties on each entity. It's a Message entity:
Message
{
int UserId; //The user generating the message
int UserIdTo; //The receiver of the message
|...| // Other stuff
}
So, I want it so that these UserId=5, UserIdTo=6 and UserId=6, UserIdTo=5 would be in the same group.
Here's my start:
var groupList = (from m in db.Messages
where m.UserId == userId || m.UserIdTo == userId
join u in db.Users on m.UserId equals u.UserId
join w in db.Users on m.UserIdTo equals w.UserId
orderby m.MessageTimestamp descending
select new DomMessage
{
MessageId = m.MessageId,
MessageContent = m.MessageContent,
MessageTimestamp = m.MessageTimestamp,
UserId = m.UserId,
UserIdTo = m.UserIdTo,
ScreenName = u.ScreenName,
ScreenName2 = w.ScreenName
}).GroupBy(m=>m.UserId == userId)
.ToList();
This does the first bit of grouping by UserId, but I'm stuck on trying to extend this so that where any UserId value in the resulting group equals the UserIdTo somewhere else add that to this group?
EDIT: I need the result to go to a List because there is other stuff I need to do with it...
Thanks!
Upvotes: 4
Views: 1828
Reputation: 656
I think this is the easiest way:
var groupList = from a in (
from m in db.Messages
where m.UserId == userId || m.UserIdTo == userId
join u in db.Users on m.UserId equals u.UserId
join w in db.Users on m.UserIdTo equals w.UserId
select new
{
MessageId = m.MessageId,
MessageContent = m.MessageContent,
MessageTimestamp = m.MessageTimestamp,
UserId = m.UserId,
UserIdTo = m.UserIdTo,
ScreenName = u.ScreenName,
ScreenName2 = w.ScreenName
})
group a by new {
UserId = a.UserId,
UserIdTo = a.UserIdTo
} into grp
orderby grp.Max(a => a.MessageTimestamp) descending
select new
{
UserId = grp.Key.UserId
UserIdTo = grp.Key.UserIdTo,
MessageId = grp.Max(a => a.MessageId),
MessageContent = grp.Max(a => a.MessageContent),
MessageTimestamp = grp.Max(a => a.MessageTimestamp),
ScreenName = grp.Max(a => a.ScreenName),
ScreenName2 = grp.Max(a => a.ScreenName2)
}
You have to tell it what to do with the fields you are not grouping by. In this case I got the MAX value for each.
Upvotes: 0
Reputation: 5319
Try this:
var payload = new[]
{
new{ To = 1, From = 2, Message = "msj1" },
new{ To = 1, From = 2, Message = "msj2" },
new{ To = 2, From = 1, Message = "msj3" },
new{ To = 4, From = 1, Message = "msj4" },
new{ To = 1, From = 3, Message = "msj5" }
};
var groupped = payload.Select(x => new { Key = Math.Min(x.To, x.From) + "_" + Math.Max(x.To, x.From), Envelope = x }).GroupBy(y => y.Key).ToList();
foreach (var item in groupped)
{
Console.WriteLine(String.Format(@"Group: {0}, messages:", item.Key));
foreach (var element in item)
{
Console.WriteLine(String.Format(@"From: {0} To: {1} Message: {2}", element.Envelope.From, element.Envelope.To, element.Envelope.Message));
}
}
Upvotes: 2
Reputation: 41757
Try the following GroupBy expression:
.GroupBy(m => Math.Min(m.UserId, m.UserIdTo) + ',' + Math.Max(m.UserId, m.UserIdTo))
Upvotes: 1