Group by with static columns and grouped columns - c#

I'm use to sql, and not quite used to linq yet. May I ask how do I group columns based on a value, and group other columns to a list and make the other columns static?
For Example
People | Businesses | StreetAddress
John | Store 1 | Hello Blvd.
John | Store 2 | Hello Blvd.
Produces
People | Businesses | StreetAddress
John | ["Store 1", "Store 2"] | Hello Blvd.
My linq query to make Table 1
from x in ctx.People
join ownership in ctx.Ownerships
on x.Id equals ownership.Owner_Id into ps
from ownership in ps.DefaultIfEmpty()
join Business in ctx.Businesses
on ownership.Business_Id equals Business.Id into ps2
from Business in ps2.DefaultIfEmpty()
select new PersonDTO
{
Id = x.Id,
Business = Business.Name,
StreetAddress = x.Addresses.FirstOrDefault().Line1
}

Assuming you need to group by both People & StreetAddress.
var result = data.GroupBy(x => new { x.People, x.StreetAddress })
.ToList()
.Select(x => new
{
People = x.Key.People,
Business = String.Join(",",x.Select(z => z.Business),
StreetAddress x.Key.StreetAddress
});
Edit:
Fetch Business in a List.
var result = data.GroupBy(x => new { x.People, x.StreetAddress })
.Select(x => new
{
People = x.Key.People,
Business = x.Select(z => z.Business).ToList(),
StreetAddress x.Key.StreetAddress
});
Here, data is the data source you want to group.

Related

How do i write this query in entity-framework

I have a table (Items) with records in this format.
Name | ProductId | Owner
Product1 | 1 | xx
Product2 | 2 | yy
Product1 | 1 | xx
Product3 | 3 | xx
Product3 | 3 | xx
Product3 | 3 | xx
Product4 | 4 | xx
Product2 | 2 | xx
Product5 | 5 | xx
I want to write entity framework query that will return the top 3 products, their names and Count. The result should look like this.
Result
Name: [Product3, Product2, Product1],
Count:[3, 2, 2]
I have checked other answers here on SO but still did not find something close to what i want. Note Name and Count returns a list of the top 3 respectively.
You can try this code
var query = context
.products
.GroupBy(p => p.Name)
.OrderByDescending(g => g.Count())
.Take(3);
products.Select(p => new
{
Name = query.Select(g => g.Key).ToList(),
Count = query.Select(g => g.Count()).ToList(),
})
.FirstOrDefault();
Although I recommend that you get top 3 product with count together from database and then put it in different list, like this :
var products = context.products
.GroupBy(p => p.Name)
.OrderByDescending(g => g.Count())
.Take(3)
.Select(g => new
{
Name = g.Key,
Count = g.Count()
})
.ToList();
List<string> names = products.Select(p => p.Name).ToList();
List<int> counts = products.Select(p => p.Count).ToList();
The following should work:
products.GroupBy(p => p.ProductId)
.OrderByDescending(g => g.Count())
.Take(3);

Linq Group by Values in a list

So Currently I have this TrackingInfo class which contains an ID and a list of EmailActionIDs, which is an int.
I have a List Of this class which the data looks like:
ID, | EmailActions
_______________
A | 1, 3, 5
B | 3, 5, 6
C | 2, 4, 6
I'm trying to write a Linq Statement To convert this into A list of IDs grouped by each individual value in the list.
So the Results Set would look like:
ID | Values
_______________
1 | A
2 | C
3 | A, B
4 | C,
5 | A, B
6 | B, C
I can't figure out how I would write the group by can anyone give me some insight.
DistinctValues = new List<int> {1,2,3,4,5,6};
TrackingInfo.Groupby(t => DistinctValues.foreach(d =>
t.EmailActions.Contains(d))).Tolist()
This ofcourse isn't working any suggestions on how to do this using Linq
Its easy enough to get a distinct list of EmailActions
var distinctEmailActions = items.SelectMany(i => i.EmailActions).Distinct();
Then pivoting this is a little complex, but here it is:
var result = distinctEmailActions.Select(e => new {
ID=e,
Values = items.Where(i => i.EmailActions.Contains(e)).Select(i => i.ID)
});
Live example: http://rextester.com/CQFDY66608
What you're looking for is SelectMany, but it's easier to use query syntax here:
var result = from item in source
from action in item.EmailActions
group item.ID by action into g
select new { ID = g.Key, Values = g.ToList() }
You can do it by first generating a range using Enumerable.Range, and then matching EmailActions, like this:
var res = Enumerable.Range(1, 6)
.SelectMany(v => TrackingInfo.Where(info => info.EmailActions.Contains(v)).Select(info => new { Id, Value = v }))
.GroupBy(p => p.Value)
.Select(g => new {
Id = g.Key
, Values = g.Select(p => p.Id).ToList()
});
You can achieve this using SelectMany & GroupBy like this:-
var result = tracking.SelectMany(x => x.EmailActionIDs,
(trackObj, EmailIds) => new { trackObj, EmailIds })
.GroupBy(x => x.EmailIds)
.Select(x => new
{
ID = x.Key,
Values = String.Join(",", x.Select(z => z.trackObj.ID))
}).OrderBy(x => x.ID);
Working Fiddle.

Optimize or ditch LINQ query?

So I have a LINQ (to SQL) query that pulls information from a database into a grid. There is a function to aggregate the grid data based on the current filter parameters which will sum the amount of recurring "X"'s in the grid data.
For instance, lets assume the grid displays customer vists to a grocery store. The original data may show the follow:
Date | Name | No. Prod | Total $
--------------------------------------------
01/02/13 | Customer A | 4 products | $23.00
01/02/13 | Customer B | 2 products | $3.26
01/02/13 | Customer C | 7 products | $47.42
01/16/13 | Customer A | 3 products | $26.22
Clicking the summation function for the clients column will display the following grid data:
Cnt| Name | Tot. Prod | Total $
--------------------------------------
2 | Customer A | 7 products | $49.22
1 | Customer B | 2 products | $3.26
1 | Customer C | 7 products | $47.42
My problem is that I am doing the summation logic in a LINQ query. I assumed this would be fast...but it is just the opposite. Here is a sample.
Expression<Func<OrdersView, bool>> filter;
filter = m => m.RecordCreated >= fromDate && m.RecordCreated <= toDate && m.DepartmentID == _depID;
var ClientAggOrders = dataContext.OrdersView
.Where(filter)
.GroupBy(m => m.Name)
.Select(gr => new
{
Name = gr.Key,
Count = gr.Where(s => s.ID != null).Count(),
id = gr.Select(s => s.ID),
S1 = gr.Sum(s => s.Tare < s.Gross ? s.Tare : s.Gross),
S2 = gr.Sum(s => s.Tare < s.Gross ? s.Gross : s.Tare),
NetWeight = gr.Sum(s => s.NetWeight),
Price = gr.Sum(s => s.NetPrice)
}
).ToList();
My question is, why is this such bad practice? LINQ allows for these expressions in the SELECT clause, but the time it takes to execute is beyond absurd to the point where I don't see it being beneficial in any real world scenario.
Am I using LINQ wrong and should I just move my logic outside of the query or can this be optimized and done within LINQ properly? Thanks for any advice!
You can use LINQPad to see the SQL that is generated.
Because of the way LINQ to SQL works, id = gr.Select(s => s.ID) causes a subquery to be executed for every group. Remove this, and instead get the ID+Name in your GroupBy: .GroupBy(m => new{m.ID, m.Name})
You should find that the generated SQL will now be a single statement, instead of the main statement plus a statement for each group.
Perform grouping only in memory? Solve your problem?
var ordersView =
dataContext.OrdersView
.Where(m => m.RecordCreated >= fromDate && m.RecordCreated <= toDate && m.DepartmentID == _depID)
.ToList();
var ClientAggOrders = ordersView.GroupBy(m => m.Name).Select(gr => new
{
Name = gr.Key,
Count = gr.Where(s => s.ID != null).Count(),
id = gr.Select(s => s.ID),
S1 = gr.Sum(s => s.Tare < s.Gross ? s.Tare : s.Gross),
S2 = gr.Sum(s => s.Tare < s.Gross ? s.Gross : s.Tare),
NetWeight = gr.Sum(s => s.NetWeight),
Price = gr.Sum(s => s.NetPrice)
}).ToList();

join list with linq-to-sql query

I have list of MyObject that looks like this:
public class MyObject{
public int FruitID {get;set;}
public string FruitName {get;set;}
}
List<MyObject> TheList = new List<MyObject>();
This list is populated with a linq-to-sql query. I'm looking to create a join between this list and a table that contains FruitID as its foreign key.
The table HarvestTimes looks like this:
FruitID | HarvestDatetime | RipeFactor
3 | 3/4/2011 | 2
3 | 4/5/2011 | 4
3 | 5/5/2011 | 3
4 | 3/21/2011 | 2
4 | 4/10/2011 | 2
4 | 5/10/2011 | 2
This is what I have so far:
var TheQuery = (from list in TheList
join fruit in MyDC.HarvestTimes on
list.FruitID equals fruit.FruitID
where ....
select new MyObject{... }).ToList();
I'm have some trouble with the Where clause. How do I get only the Fruit where the RipeFactor was always 2. For instance, Fruit 3 has a RipeFactor of 2 but also has 4 and whereas only Fruit4 has only 2s. I tried with Contains but both fruits come up.
Thanks for your suggestions.
Assuming there is a Relationship between the tables HaverstTime and Fruit:
var TheQuery = MyDC.HarvestTimes
.Where(p => TheList.Select(q => q.FruitID).Contains(p.FruitID))
.GroupBy(p => p.Fruit)
.Where(p => p.All(q => q.RipeFactor == 2))
.Select(p => p.Key);
This will create a IEnumerable<Fruit> which I think can be easily converted to MyObject.
Update:
Oops I forgot to add TheList.Select(q => q.FruitID). That's why it didn't compile.
Sorry =)
Update2:
Do the same, considering Ripefactor = 2 and 3
var TheQuery = MyDC.HarvestTimes
.Where(p => TheList.Select(q => q.FruitID).Contains(p.FruitID))
.GroupBy(p => p.Fruit)
.Where(p => p.All(q => q.RipeFactor == 2 || q.RipeFactor == 3))
.Select(p => p.Key);
I think this would work
var fruit = (from list in TheList
join fruit in
(from fr in MyDc.HarvestTimes
group fr by fr.FruitID into fg
where !fg.Any(f => f.RipeFactor != 2)
select fg)
on list.FruitID equals fruit.Key
select new MyObject{... }).ToList();
Update - If you only want to return the distinct list of FruitIDs you need to select fg.Key instead of fg
var fruit = (from list in TheList
join fruit in
(from fr in MyDc.HarvestTimes
group fr by fr.FruitID into fg
where !fg.Any(f => f.RipeFactor != 2)
select fg.Key)
on list.FruitID equals fruit
select new MyObject{... }).ToList();

Remove Duplicate based on column value-linq

i have many to many relationship between employee and group. following linq statement
int[] GroupIDs = {6,7};
var result = from g in umGroups
join empGroup in umEmployeeGroups on g.GroupID equals empGroup.GroupID
where GroupIDs.Contains(g.GroupID)
select new { GrpId = g.GroupID,EmployeeID = empGroup.EmployeeID };
returns groupid and the employeeid. and result is
GrpId | EmployeeID
6 | 18
6 | 20
7 | 19
7 | 20
I need to remove the rows for which the employeeid is repeating e.g. any one of the row with employeeid= 20
Thanks
Okay, if you don't care which employee is removed, you could try something like:
var result = query.GroupBy(x => x.EmployeeId)
.Select(group => group.First());
You haven't specified whether this is in LINQ to SQL, LINQ to Objects or something else... I don't know what the SQL translation of this would be. If you're dealing with a relatively small amount of data you could always force this last bit to be in-process:
var result = query.AsEnumerable()
.GroupBy(x => x.EmployeeId)
.Select(group => group.First());
At that point you could actually use MoreLINQ which has a handy DistinctBy method:
var result = query.AsEnumerable()
.DistinctBy(x => x.EmployeeId);

Categories

Resources