Linq count products for a specific customer - c#

hi I have this query that count all the products sold and now I want to change it so it counts the amount of products for a particular customer. Anyone can help me please? Tables= table customer one2many transactions one2many transactionitems many2one product many2one producttype
var query = from product in cse.tblTransactionItems
group product by product.tblProduct.Description into g
select new { ProductId = g.Key, totalUnitsSold = g.Count() };

You could consider grouping by multiple columns.
var query = from product in cse.tblTransactionItems
group product by new
{
product.tblProduct.Description,
product.tblProduct.Customer // put the customer here.
} into g
select new
{
Product = g.Key.Description,
Customer = g.Key.Customer,
totalUnitsSold = g.Count()
};
This way the totalUnitsSold is a total for a specific customer and product.
Note: If your customer is in another table, you'll need to join first. The above simply assumes customer to be part of your existing table.

Related

How to change values of few properties from one list to another using LINQ C#:

I have two list like
List<Customer> customer = new List<Customer>()
{ Id =1 , Name = 'Demo1' , OrderId = 123}
{ Id =1 , Name = 'Demo2' , OrderId = 123}
List<Order> order = new List<Order>()
{ Id =77 , CustomerName = 'Demo1'}
{ Id =88 , CustomerName = 'Demo2'}
I want to replace customer.OrderId = order.Id where order.CustomerName = customer.Name
I want to replace customer list OrderId value from order list when CustomerName is matching with Name prop
I was trying something like this -
customer = order.Select(eo => new Customer { Name = eo.CustomerName });
this is not correct LINQ can anyone correct me here?
LINQ is primarily suited for querying, not data modification.
Instead, I would just use simple foreach:
foreach (var c in customer)
{
var o = order.FirstOrDefault(o => o.CustomerName == c.Name);
c.OrderId = o?.Id ?? 0;
}
Of course this approach will not work as well when there are multiple orders per customer. Also I would advise to rename the variables to plural - customers and orders to better denote their meaning.
For a purely LINQ approach, you could write a ForEach LINQ extension method, but I find an explicit foreach a more readable solution.
LINQ is primarily used for querying. You can make a new list that matches your requirements.
If desired you can assign this new list to your variable customers.
You want to join your customers and orders on the name of the customer.
Simple solution:
var joinResult = customers.Join(orders, // join the tables of customers with orders
customer => customer.Name, // from every customer take the Name
order => order.CustomerName, // from every order take the CustomerName
(customer, order) => new Customer // when they match make a new Customer
{
Id = customer.Id, // take Id and Name from the matching Customer
Name = customer.Name,
OrderId = order.Id, // take the OrderId from the matching order
})
.ToList();
customers = joinResult;
Alas, this won't work if you have a Customer with several Orders:
var customers = new List<Customer>()
{ Id = 1 , Name = 'John Doe' , OrderId = 123},
var orders = new List<Order>()
{ Id =77 , CustomerName = 'John Doe'}
{ Id =88 , CustomerName = 'John Doe'}
Should Customer 1 have OrderId 77 or 78?
Are you sure that every Customer has only one Order?
To get a Customer with all his Orders use GroupJoin
var result = customers.GroupJoin(orders, // GroupJoin the customers with orders
customer => customer.Name, // from every customer take the Name
order => order.CustomerName, // from every order take the CustomerName
(customer, orders) => new // for every customer with all his matching orders
{ // make one new object
Id = customer.Id, // take Id and Name from the matching Customer
Name = customer.Name,
// TODO Decide what to do if there are several orders for customer with this name
// Keep all orders? Or keep the oldest one, the newest one?
// the unpaid ones?
AllOrders = orders.ToList(),
OldestOrder = orders.Orderby(order => order.Date).FirstOrDefault(),
NewestOrder = orders.OrderByDescending(order => order.Date).FirstOrDefault(),
UnpaidOrders = orders.Where(order => order.Status == Status.Unpaid).ToList(),
})
.ToList();
You want to perform a join operation (most likely an inner join). LINQ provides such a feature
var customerOrders = customer.Join(order,
c => c.Name,
o => o.CustomerName,
(customer, order) =>
{
custumer.OrderId= order.Id;
return customer;
}).ToList();
But as #Martin Zikmund says i'd be carefull with manipulation the data directly.
You need to join both lists on property Name from customer and property CustomerName from order and then assign OrderId from Order like
List<Customer> result = new List<Customer>();
result = (from c in customer
join o in order on c.Name equals o.CustomerName
select new Customer
{
Id = c.Id,
Name = c.Name,
OrderId = o.Id
}).ToList();
foreach (var item in result)
{
Console.WriteLine($"Id: {item.Id}, \t Name: {item.Name}, \t OrderId: {item.OrderId}");
}
Console.ReadLine();
Output:
You can loop through pairs of customer and correspondent orders and update customers for only matched pairs.
var matched = customers.Join(orders,
customer => customer.Name,
order => order.CustomerName,
(customer, order) => (Customer: customer, Order: order));
foreach (var pair in matched)
{
pair.Customer.OrderId = pair.Order.Id;
}
Notice that in case when order collection contains more than one order with same customer name, Join approach will update customer with order Id occurred last in the collection.
LINQ extension methods designed in "functional" way, where enumerated items handled as immutable. LINQ methods always return new instance of the collection. Most of the developers will be "very" surprised if items will be mutated during enumeration methods.
So having explicit foreach loop will clearly tell other developers of your intentions.

group by issue with extra columns

I group the result on the customers zipcode. For each zipcode, I want to see the amount of bookings and the amount of equipment that is ordered.
So far my code looks like this:
var statistics = from b in db.Bookings
from c in db.Customers
where b.customerID == c.id
group c by c.zipcode into stat
select new {
Zipcode = stat.Key,
NumberOfBookings = stat.Count()
};
This code groups result into zipcodes and gives me the amount of bookings in each zipcode. How to get the amount of equipment also?
Rather than using joins like in SQL, you can (and it's better) use the navigation properties from your model:
var statistics =
from b in db.Bookings
group b by b.Customer.zipcode into g
select new
{
Zipcode = g.Key,
NumberOfBookings = g.Count(),
NumberOfEquipments = g.SelectMany(b => b.Equipments).Count(),
};
Note that the g variable represents a set of bookings with the same zipcode, so SelectMany is used to get all associated equipments before applying the Count operator.
Of course that's not the only way, for instance you can use Sum instead:
NumberOfEquipments = g.Sum(b => b.Equipments.Count())

LINQ - ENTITY: Need to return a list of count of rows in ANOTHER table

I have a system with a table PRODUCTS and FAULTS. Each product can have a number of faults (the fault table has a foreign key ProductID). I need to get a list of aproximately ten products with the most number of faults. I tried the following but it doesn't seem to be work (the fields that i need are the product name, price, id and the number of faults):
return (from p in Entity.Products
join f in Entity.Faults
on p.ProductID equals f.ProductID
group f by new { f.ProductID, p.Name, p.Price } into product
select new CountFaultView()
{
ProductID = product.Key.ProductID,
Name = product.Key.Name,
Price = product.Key.Price,
FaultsCount = product.Key.Name.Count()
}
).OrderByDescending(x => x.FaultsCount).Take(10);
}
I am TRYING to count the number of times that the name is displayed but obviously I seem to be getting something wrong ;o

How can I get the count in linq?

I have table called products with columns:
productid ,
productname,
productprice
categoryid
My problem is I want to get the number of products depending on product name along with details. I want to show the data in DataGridView. How can I know the number of products for a single product name like below?
productid productname productavailable productprice
--------------------------------------------------------------------------
1 product A 2 products(product A) 100
2 product B 5 Products(product B) 200
Like the above table I have to display in DataGridView. I am using LINQ and C# and my DbContext name is tsgdbcontext.
Use GroupBy with a key that contains your grouping properties. Then select out the key properties along with the count of each from the grouping.
var query = tsgdbcontext.Products
.GroupBy(p => new {
p.ProductId,
p.ProductName,
p.ProductPrice
})
.Select(g => new {
g.Key.ProductId,
g.Key.ProductName,
g.Key.ProductPrice,
Available = g.Count()
});
Not sure I am understanding exactly + making some assumptions but here is an example linq query that produces a count based on some arbitrary selection criteria (id=2 and price greater than 100)...
int count = (from p in tsgdbcontext.Products
where p.productid == 2 && p.productprice > 100
select p).Count();

LinqToSql: Select field from list used within a query

I perform a query on a table Installation to get a list of Ids that are needed to query a table Product on a different database (before you ask, it has to be this way, can't query across dbs). Here's what the list looks like:
class Installation
{
Guid InstallationId
Guid ProductId
}
List<Installation> installs;
I don't have any problems using this list for the query in to the Product table which looks like this:
var prods = (from p in context.Product
where installs.Select(i => i.ProductId).Contains(p.ProductId)
select new
{
ProductNumber = p.ProductNumber
// How do I get InstallationId from installs??
}).ToList();
What I need to know is how I can retrieve InstallationId from the list and store it in the new list?
Thanks in advance.
You should do a join
var products = (from product in context.Product
join install in installs
on install.ProductId equals product.ProductId
select new {
ProductNumber = product.ProductNumber
InstallationId = install.InstallationId
}
).ToList();
A slight refactoring of Jason's answer to allow for the LinqToSql exception.
var products = (from product in context.Product
where installs.Select(i => i.ProductId).Contains(p.ProductId)
select product).ToList()
var installedProducts = (from product in products
join install in installs
on install.ProductId equals product.ProductId
select new
{
ProductNumber = product.ProductNumber,
InstallationId = install.InstallationId
}).ToList();

Categories

Resources