I have 2 tables, Category and ProductCategory.
A product can have multiple categories:
Category
CategoryIdCategoryName
1
Electronics
2
E-Reader
3
Tablet
ProductCategory
CategoryIdProductId
1
100
2
100
3
100
3
500
1
800
I have a repository set up for Category that has a navigation property to ProductCategory.
I am trying to construct a LINQ query that takes a CategoryId and return me a list of all the
associated Categories + Number of times it is associated (Association being through product).
For example if we take CategoryId 1 (Electronics) from the above example:
We can see that 1 is linked to ProductId 100 and 800 but at the same time ProductId 100 is linked to Categories 2 & 3. We also see that CategoryId 2 is linked one times to ProductId 100 and CategoryId 3 is linked 2 times to ProductIds 100 and 500.
My expected result set would be (excluding the CategoryId of 1 that was passed in)
CategoryIdAssociation(s)
2
1
3
2
But My problem is if I do something like this:
var resultSet = repository.Query()
.Include(pc => pc.ProductCategory)
.Where(c => c.CategoryId == 1).ToList();
the resultSet is only restricted to
CategoryIdProductId
1
100
1
800
but using above LINQ I want to shape the resultSet to:
CategoryIdAssociation(s)
2
1
3
2
Any ideas ?
You're looking for the count of associations which is an aggregate function that you can use directly against a grouped selection from product category.
var results = ProductCategory
.GroupBy(g => g.CategoryId)
.Select(new {
Category = g.Key,
Associations = g.Count()
})
.ToList();
Related
I have data in a single database table like so:
Id NameId EndNumber SortOrder
1 TestA 1 1
1 TestA 3 2
1 TestA 9 3
1 TestB 1 1
1 TestB 2 2
1 TestB 4 3
1 TestB 6 4
1 TestB 7 5
1 TestC 2 1
1 TestC 4 2
1 TestC 6 3
I have a LINQ query like this:
result = _getService.QueryWithNoTracking<GetNamesId>()
.Where(q => q.Id == myId && names.Contains(q.NameId)
I want to my select to return this:
Id NameId EndNumber
1 TestA 9
1 TestB 7
1 TestC 6
I essentially want the max sort order value of each id/nameId combination. I understand the select but not sure if/how to use an OrderBy to achieve this.
You'd probably use groupby for this, rather than OrderBy
result = _getService
.QueryWithNoTracking<GetNamesId>()
.Where(q => q.Id == myId && names.Contains(q.NameId))
.GroupBy(gni => gni.NameId)
.Select(g =>
new {
Id = g.First().Id,
NameId = g.Key,
EndNumber = g.Max(gni => gni.EndNumber)
}
);
LINQ grouping is slightly different to sql. It takes a single list of items and produces a "list of lists" where every item in the inner list has the same property that was specified for key. By grouping on NameId you get a list of lists, which you then turn back into a single list by throwing away most of the EndNumbers in the inner lists and just keeping the max value
I have an unsorted array of objects with CustomerId, ProductId and Count (all ints)
I want to combine records where CustomerId and ProductId match, summing the count.
for example:
CId PId Cnt
1 100 5
1 100 1
2 100 7
Desired output:
CId PId Cnt
1 100 6
2 100 7
As you can see for the two records for CId 1 & PId 100 have been merged and the count has been summed.
Can this be done with LINQ?
I know it could done with loops but I'm hoping for a more elegant way
Here I have assumed that the class name is Item:
var result = array.GroupBy(x => new { x.CId, x.PId })
.Select(g => new Item { CId = g.Key.CId, PId = g.Key.PId, Cnt = g.Sum(x => x.Cnt) });
Here is a Live Demo
First things first - I am connecting to an SqlServerCe database using C# in visual studio 2012.
I am using Entity framework 6 and Linq to perform this function.
So - On to the question.
I have a table as follows
ItemGroup
(
ID INT PRIMARY KEY,
ItemID INT,
GroupID INT
)
There are two tables that link to this (Items and Groups) via their IDs and the two foreign key columns in the Item Group table.
Each Item can be part of one groups and each group can have many items.
If an Item has a group ID of 0 then it is considered to not be part of a group
the result of this is that there are about 3000 groups each with 2 -> ~30 items, but there is one group that has about 4000 items.
My problem is that I have a list of items, and I want to return only one from each group unless the item is part of group 0 (ie no group). In the case of group 0 I want to return all items that match.
for example:
**Group 0**
*Item 1,
Item 2,
Item 3,*
**Group 1**
*Item 4,
Item 5*
**Group 2**
*Item 6,
Item 7,
Item 8*
**Group 3**
*Item 9*
I have list of the following items:
*Item1, Item2, Item4, Item5, Item6, Item7*
In this case I want to output all the items from my list that are in group 0 so:
*Item1, Item2*
Item 4 is part of group 1 so we want to display that, but as item 5 is part of the same group we do not want that, so the remainder of my list would be displayed as follows:
*Item4, Item6*
Giving a full list of:
*Item1, Item2, Item4, Item6*
I have tried several approaches, mainly through the use of a Union whereby I get all those records that are part of group 0 first, then do a group by first on the other records then union them together to get the final results.
However this seems tremendously inefficient and takes an age to perform - not to mention the Linq statement is very difficult to follow.
Can someone point me in a direction that I might be able to follow in order to perform this function?
You want to use SelectMany(), conditionally returning all or just one of the grouped sequences depending on the group ID:
var result = (from item in data
group item by item.Group)
.SelectMany(group => group.Key == 0 ? group : group.Take(1));
This code will give you results for the non zero group. Similarly you can figure out the other group. I hope this helps.
var query1 = from t in context.Table1
where t.GroupID != 0
group t by t.GroupID into g
select new
{
ID = g.Key,
Groups = g.Take(1)
};
Console.WriteLine("items with non 0 group");
foreach (var item in query1)
{
foreach (var g in item.Groups)
{
Console.WriteLine(" ID " + g.ID + " " + "Group ID " + g.GroupID + " " + " Item ID " + g.ItemID);
}
}
Input data
ID ItemID GroupID
1 1 0
2 2 0
3 3 0
4 4 1
5 5 1
6 6 2
7 7 2
8 8 2
Output generated
items with non 0 group
ID 4 Group ID 1 Item ID 4
ID 6 Group ID 2 Item ID 6
Say we got a Database design like this.
Customer
Id Name
1 John
2 Jack
Order
Id CustomerId
1 1
2 1
3 2
OrderLine
Id OrderId ProductId Quantity
1 1 1 10
2 1 2 20
3 2 1 30
4 3 1 10
How would I create an entity framework query to calculate the total Quantity a given Customer has ordered of a given Product?
Input => CustomerId = 1 & ProductId = 1
Output => 40
This is what I got so far, through its not complete and still missing the Sum.
var db = new ShopTestEntities();
var orders = db.Orders;
var details = db.OrderDetails;
var query = orders.GroupJoin(details,
order => order.CustomerId,
detail => detail.ProductId,
(order, orderGroup) => new
{
CustomerID = order.CustomerId,
OrderCount = orderGroup.Count()
});
I find it's easier to use the special Linq syntax as opposed to the extension method style when I'm doing joins and groupings, so I hope you don't mind if I write it in that style.
This is the first approach that comes to mind for me:
int customerId = 1;
int productId = 1;
var query = from orderLine in db.OrderLines
join order in db.Orders on orderLine.OrderId equals order.Id
where order.CustomerId == customerId && orderLine.ProductId == productId
group orderLine by new { order.CustomerId, orderLine.ProductId } into grouped
select grouped.Sum(g => g.Quantity);
// The result will be null if there are no entries for the given product/customer.
int? quantitySum = query.SingleOrDefault();
I can't check what kind of SQL this will generate at the moment, but I think it should be something pretty reasonable. I did check that it gave the right result when using Linq To Objects.
Is there a way to write a Linq statement to find duplication in Column B, and only find it when Column A has duplicated values then add the value of Column B to the Column where the duplication is found. Any help is appreciated thanks.
RecordID CartID Quantity ProductID
1 11 3 3
2 12 5 6
3 11 6 3
Delete record 3 and add 6 to the Quantity of RecordID 1 so that it becomes:
RecordID CartID Quantity ProductID
1 11 9 3
2 12 5 6
var records = (from i in list
group i by i.CartID into g
select new Item()
{
RecordID = g.Min(o => o.RecordID),
CartID = g.Key,
Quantity = g.Sum(o => o.Quantity),
ProductID = g.Min(o => o.ProductID)
}).ToList();
This sums all the quantity of items with the same CartId creating only the min occurent RecordId and ProductId as you asked. Selecting the min ProductId is something I needed to do to make the query work.
That is why I think you miss some grouping on ProductId...
You did not ask for this, but I think this is what you want (because it makes common sense to not group apples and pears together). (It gives the same result on the sample data provided but for different ProductsIds it will have different results.
var records = (from i in list
group i by new { cartID = i.CartID, prodID = i.ProductID } into g
select new Item()
{
RecordID = g.Min(o => o.RecordID),
CartID = g.Key.cartID,
Quantity = g.Sum(o => o.Quantity),
ProductID = g.Key.prodID
}).ToList();
This groups by CartID and ProductId. Multi-field grouping in Linq is achieved with anonymous types.