Group by with linq to update collection - c#

I have a IEnumerable collection called allEventsDetails and collection properties
are Digit, Name and status.
I need to update the same collection if Two or more Digits values are equal.
var categories = from p in allEventsDetails
group p by p.Digit into g
where g.Count() > 1
select g.Select(s => s.status = "true");
How can I use linq to do this?

you could do something like this:
(from x in allEventsDetails
group x by x.Digit into y
where y.Count()>1
select y).SelectMany(z=>z).ToList().ForEach(x=>x.Status="true");
What you could also do is:
var temp= (from x in allEventsDetails
group x by x.Digit into y
where y.Count()>1
select y).SelectMany(z=>z);
foreach (var x in temp)
{
x.Status= "test";
}
This way you don't have to create a "temporary" list.

Related

Fields not visible after groupby?

What I have now:
var batch_pymnts2 = (from a in ctx.WarehouseStatementBatchPayments
join b in ctx.WarehouseStatementBatches on a.WarehouseStatementBatchID equals b.ID
join c in ctx.WarehousePaymentInvoices on a.ID equals c.WarehouseStatementBatchPaymentID
where b.ID == batchID
select new
{
PaymentId = a.ID,
PaymentNet = a.Net,
PaymentType = a.Type
})
.GroupBy(d => d.PaymentId).Where(x => x.Count() == 1);
I need to query these results like so:
var test = (from a in batch_pymnts2 where a.PaymentNet > 100 select a).ToList();
However, I cant see the fields of the (anonymous) type that the first statement uses to project the results into.
Will I need to use a defined type in the query for the projection? Is there a way to do it with anonymous types?
[update]
I managed to change the source query a bit, moving the group by inside and before the group by. This lets the fields of the anonymous type being projected, be "exposed" in further statements.
var count2 = (from a in WarehouseStatementBatchPayments
join b in WarehouseStatementBatches on a.WarehouseStatementBatchID equals b.ID
join c in WarehousePaymentInvoices on a.ID equals c.WarehouseStatementBatchPaymentID
group a by a.ID into grp
from d in grp
where d.WarehouseStatementBatchID == batchID && grp.Count() == 1
select new { PaymentId = d.ID, PaymentNet = d.Net, PaymentType = d.Type }).ToList();
batch_pymnts2 is a sequence of group objects. In effect, it is a collection of collections of your anonymous type. Each item in batch_pymnts2 has this:
group.Key; /* a PaymentId value */
((IEnumerable)group); /* the anon type items grouped together in this group */
Those group objects implement the IGrouping interface. Their Key property is the PaymentId values that define the groups. If you enumerate the groups (they implement IEnumerable<T>), you'll get the anonymous objects that you grouped by PaymentId:
var test = batch_pymnts2.SelectMany(g => g.Where(anon => anon.PaymentNet > 100));
test is now an enumeration of your anonymous type, because we have now enumerated a subset of the anon items from each of the groups, and (in effect) unioned all those little enumerations of anon back into one big one.
If you want to select groups which have at least one anonymous thingy with PaymentNet > 100, try this:
// Groups which have at least one PaymentNet > 100
var t2 = batch_pymnts2.Where(g => g.Any(anon => anon.PaymentNet > 100));
// PaymentIds of the groups which have at least one PaymentNet > 100
var ids = t2.Select(g => g.Key);
// PaymentIds that appear only once
var singles = t2.Where(g => g.Count == 1).Select(g => g.Key);
I don't know why you're grouping them, or what your PaymentNet > 100 query is meant to accomplish, so I'm not sure exactly how to write the query you want. But your starting point is that you're querying a sequence of group objects which contain enumerations of your anonymous type -- not a sequence of that type itself.

Filter LINQ entity include query

I have the following two tables
Groups
Id (int)
People
Id (int)
GroupId (int, Groups.Id)
IsSelected (bit)
This will return all Groups with all their members(People) in a single query
var grps = myDatabase.Groups.Include("People");
How can I write a single query that will return all Groups with People who has been selected(IsSelected = true)?
let me know if this works
var grps = myDatabase.Groups.Select(g=> new { g, people = g.People.Where(p=>p.IsSelected)});
You will want to use the 'join' method, like this:
(from g in myDatabase.Groups
join p in myDatabase.People on g.Id equals p.GroupId
where p.IsSelected == true
select g);
This will give you all groups where there are people selected.
OR check out .Where()
Something like
var grps = myDatabase.Groups.Include("People").Where(x => x.IsSelected);
//x => !x.IsSelected for false

How do I access specific rows in my LINQ model?

I currently have a linq query to select 5 random rows from my products table. Once I have the collection in my model how do I access a specific row? I'm using First() to get at my first row but Im not sure what I would use if I wanted to get data from the 3rd row in that query.
Thanks!
var Model = (from r in DB.Products select r).OrderBy(r => Guid.NewGuid()).Take(5);
var ProductID1 = Model.First().ProductID;
var ProductID3 = Model.???
You should only run the query once and then iterate over the rows using foreach or just use the index property to select the appropriate product
var Model = (from r in DB.Products select r).OrderBy(r => Guid.NewGuid()).Take(5).ToList();
var ProductID1 = Model[0].ProductID;
var ProductID2 = Model[1].ProductID;
var Model = (from r in DB.Products select r)
.OrderBy(r => Guid.NewGuid())
.Take(5).ToArray();
var ProductID1 = Model.First().ProductID;
var ProductID3 = Model.Skip(2).First() <-- 3rd row
I added ToArray() to the initial query, based on Douglas' comment. Otherwise, the query will re-run every time you pull anything out (since linq's .Take(n) is deferred).
You could simply iterate over your result collection, and take the nth index that you want.
Product product = null;
int index = 0;
foreach (Product p in DB.Products)
{
if (index == 3)
{
product = p;
break;
}
index++;
}
If you process your query into a List, you can access each element directly by index:
var Model = (from r in DB.Products select r)
.OrderBy(r => Guid.NewGuid())
.Take(5)
.ToList(); //Process into a list
var ProductID1 = Model[0].ProductID;
var ProductID3 = Model[3].ProductID;
...
var ProductID100 = Model[100].ProductID;

Return full results linq grouping query

I'm trying to group and still retrieve all the data in the table. I'm still pretty new to Linq and can't seem to tell what I'm doing wrong. I not only want to group the results but I still want to retrieve all the columns in the table. Is this possible?
(from r in db.Form
orderby r.CreatedDate descending
group r by r.Record into myGroup
where myGroup.Count() > 0
where (r.CreatedDate > lastmonth)
where r.Name == "Test Name"
select new { r, myGroup.Key, Count = myGroup.Count() }
)
Some how "r" loses its context or since I grouped "r" it has been replaced. Not sure.
You need to split your task into two steps to accomplish what you want.
Group data
var groupedData = db.Form.Where(item=>item.CreatedDate > lastMonth && item.Name == "Test Name")
.OrderByDescending(item=>item.item.CreatedDate)
.GroupBy(item=>item.Record)
.Select(group => new {Groups = group, Key = group.Key, Count = group.Count()})
.Where(item => item.Groups.Any());
From the grouped data select Form elements
var formElements = groupedData.SelectMany(g => g.Groups).ToList();
Since you're filtering on individual records, you should filter them before grouping rather than after:
(
from r in db.Form
where r.CreatedDate > lastMonth)
where r.Name == "Test Name"
orderby r.CreatedDate descending
group r by r.Record into myGroup
where myGroup.Count() > 0
select new { Groups = myGroup, myGroup.Key, Count = myGroup.Count() }
)
// Groups is a collection of db.Form instances

Group items and select specific item from each group with LINQ

There has got to be a one-liner to do this, and I just can't find it.
Given this query:
from x in new XPQuery<XPContent>(s)
select new { x.Category, x.ContentType, x.Name, x.ContentID, x.Date }
I need to select the record with the greatest date for each distinct ContentID. Can this be done cleverly with LINQ? Right now I'm doing this:
var q = (from x in new XPQuery<XPContent>(s)
select new { x.Category, x.ContentType, x.Name, x.ContentID, x.Date }).ToList();
var r = q.ToLookup(item => item.ContentID);
foreach (var rItem in r) {
var s = rItem.OrderByDescending(a => a.Date).First();
/* do stuff with s */
}
... but the ToLookup feels kind of clunky. Or do I have the best (simplest) solution?
Also, I know I shouldn't be using ToList, but please just ignore that for the time being.
Thanks in advance!
I think you want:
var q = from x in new XPQuery<XPContent>(s)
group x by x.ContentID into g
let latest = g.OrderByDescending(a => a.Date).First()
select new
{
latest.Category, latest.ContentType,
latest.Name, latest.ContentID, latest.Date
};
(Do note that there are more performant ways of finding the 'maximum' element from a group than by sorting it first, for example with a MaxBy operator.)
The query is quite simple; it just groups items by their ContentId, and then from each group, selects an instance of an anonymous type that is produced from the group's latest item.

Categories