Fetch top N rows of the table in Entity Framework - c#

I'm kind of stuck with a problem that I'm having.
Among others, I have this tables in my DB:
Product (int productId, ...otherProductInfo)
Customer (int customerId, ...otherCustomerInfo)
SoldToData ( int productId, int customerId)
I want to get top ten selling products using Entity Framework in MVC2. How can I do that?
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Following thekip's and Pr0fess0rX's advices, this is what I have done so far, and it seems to be working:
using (Entities db = new Entities())
{
var groupedProducts = (from p in db.Products
join s in db.SoldToData
on p.productId equals s.productId
group p by p.id
into ProductGroup
orderby ProductGroup.Count() descending
select ProductGroup).Take(10).ToList();
List<Products> products = new List<Products>();
products.AddRange(groupedProducts.Select(gp => gp.First()));
}
Is this the proper way?

If you have an IQueryable to query the datasource you could use orderby etc for ordering followed by Take(10)?

Join both products and customer
Group them and get the count of products per customer
Order descending by the count.
Take top 10 of the times
Get the name of the result products (top 10)

Related

LINQ Unable to get distinct value from many to many Entity Framework

I am using linq to query many to many relationship
I have those tables/entities :
Each order has multiple products and I want to get distinct order with products.
Here is my query:
var query = (from order in db.Order
join orderproduct in db.OrderProduct
on order.orderId equals orderproduct.OrderId
join product in db.Product
on orderproduct.ProductId equals product.productId
select new
{ order.orderId,
order.name,
product.productId,
product.productName,
product.price
}).Distinct().ToList();
This is the result :
I want to get only name "Jane" with 2 products. The result is showed 2 records with same name "Jane".
How to get one record name "jane" and 2 products?
Thanks for your help.
use the following:
var query = (from order in db.Order
join orderproduct in db.OrderProduct
on order.orderId equals orderproduct.OrderId
join product in db.Product
on orderproduct.ProductId equals product.productId
select new {order.orderId,order.name,product.productId,product.productName,product.price}).GroupBy(order=>order.orderId).ToList();
If you want to return a structure containing the customer's name and its ordered products, I recommend to group the products by order.orderName (not order.orderId) and to load the result into a dictionary:
var query = from order in db.Order
join orderproduct in db.OrderProduct on order.orderId equals orderproduct.OrderId
join product in db.Product on orderproduct.ProductId equals product.productId
group product by order.orderName into orderGroup
select orderGroup;
var orderedProductsByName = query.ToDictionary(name => name.Key, products => products.ToList());

How to turn a SQL Query Into Linq? "People who viewed this product also viewed this product."

I'm not really that good at linq so im having trouple trying to do groups and order by.
The goal of my query is, When someone is on a product page i want to show a list of products that people also viewed. I'm pretty sure this query is right but i have no idea how to to transfer to linq and get it to work in my C# project.
The Sql Query im trying to change to linq is
select pv.ProductId,p.Name, count(*) as 'ProductCount'
from Products p
join ProductVieweds pv
on p.ProductID = pv.ProductId
where UserId in (
select UserId
from ProductVieweds pv
where ProductID = 1 --The 1 in this example is the product the person is viewing.
)
and p.ProductID != 1 --change this
group by pv.ProductId,p.Name
order by 'ProductCount' desc
What I've been able to do so far.
var sub = (
from p in db.ProductsViewed
where p.ProductId == product.ProductID
select p.UserId).ToList();
var products = (from p in db.Products
join pv in db.ProductsViewed on c.ProductID equals p.ProductId
where p.ProductID != currentProduct.ProductID
where sub.Contains(pv.UserId)
select p).GroupBy(c => c.ProductID).ToList();
PeopleAlsoViewedModel model = new PeopleAlsoViewedModel
{
Products = products,
};
The Model
public class PeopleAlsoViewedModel
{
public IEnumerable<Product> Products { get; set; }
}
So i want to be able to group by Products and order by the count but i dont know how to do this and still get a IEnumerable< Product >. Please any help will be awesome, and if your gonna down vote at least tell me why.
Ok so I figured how to solve my problem and thought i should post it incase anyone reads this later.
The Query will look like this in C#
var products = (from c in db.Products
join p in db.ProductsViewed on c.ProductID equals p.ProductId
where c.ProductID != CurrentProduct.ProductID
where sub.Contains(p.UserId)
group c by c.ProductID into productGrouped
orderby productGrouped.Key
select productGrouped).SelectMany(group => group.Distinct()).ToList();
The SelectMany() turns the List< IGrouping< key, element>> into List< Element> I put distinct because multiple people can view the same product otherwise it returns duplicates.

Linq group by, orderbydescending, and count

So I'm trying to do a linq statement to group two db tables and select the top 25 based on how many reviews each category has. So my sql statement is
SELECT TOP 25 BusinessCategories.Category, COUNT(*) as count
FROM Reviews
JOIN BusinessCategories
ON BusinessCategories.BusinessID=Reviews.BusinessID
GROUP BY BusinessCategories.Category
ORDER BY count desc
Which works perfectly. So now to try to do this in my web api I'm having troubles. This is what I have:
var top = (from review in Db.Reviews
from category in Db.BusinessCategories
where review.BusinessID == category.BusinessID
group review by category into reviewgroups
select new TopBusinessCategory
{
BusinessCategory = reviewgroups.Key,
Count = reviewgroups.Count()
}
).OrderByDescending(x => x.Count).Distinct().Take(25);
This gives me some of the same results, but it looks like when I call the api in the browser all the counts are the same...so I'm doing something wrong.
Try this may be it works for you
var top = (from review in Db.Reviews
join category in Db.BusinessCategories
on review.BusinessID equals category.BusinessID
group review by category into reviewgroups
select new TopBusinessCategory
{
BusinessCategory = reviewgroups.Key,
Count = reviewgroups.Key.categoryId.Count() //CategoryId should be any
//property of Category or you
//can use any property of category
}).OrderByDescending(x => x.Count).Distinct().Take(25);
Solve the problem by using this
[HttpGet]
[Queryable()]
public IQueryable<TopBusinessCategory> GetTopBusinessCategories()
{
var top = (from p in Db.BusinessCategories
join c in Db.Reviews on p.BusinessID equals c.BusinessID into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.Category into grouped
select new TopBusinessCategory
{
BusinessCategory = grouped.Key,
Count = grouped.Count(t => t.BusinessID != null)
}).OrderByDescending(x => x.Count).Take(25);
return top.AsQueryable();
}

Get the "latest" datetime from a large linq query that currently returns every record that has a datetime

I have a fairly long linq query and everything works as it should.. but in a final join i am doing an innerjoin on a table that has a log, the log returns more than 50 records, i just want the latest record..
Here is an example
var tst = from w in context.storage
join p in context.products on w.id equals p.wid
join l in context.logger on p.id equals l.pid
select new
{
storageid = w.id,
productid = p.id
productname = p.name
bought = l.when
};
So a quick explanation of what happens, each product is stored in a storage center and there is a log when that product was bought, if it was bought 100 times then there is 100 records in the logger.
So currently it returns 50 records for productid = 5 ... why .. because it was bought 50 times but i only want 1 record, hence i only want the latest date time for from the logger.
Can anyone help? I am a little stuck.
Use result.Distinct(x => x.Prop) to get unique entries only
Use result.Max(x => x.Prop) to get latest date, and Min() to get earliest.
This is a case where you want to restrict to collection of records on which to join, which you can do by coding the join manually (sort of):
from w in context.storage
join p in context.products on w.id equals p.wid
// "manual" join:
from l in context.logger.Where(l => l.pid == p.id).OrderByDescencing(l => l.when).Take(1)
select new
{
storageid = w.id,
productid = p.id
productname = p.name
bought = l.when
};
In fluent linq syntax this is a SelectMany with a result selector.

linq group query into my mvc model

I have 2 tables within my EF4 project. They dont have a join.
CustomerTable
CustomerId
ConsumerName
AllowEmails
PurchaseTable
PurchaseId
CustomerId
PurchaseDate
......
What I am trying to do is return a grouped Customer when they have transactions within the PurchaseTable. If they haven't made any purchases or consumer Id isn't yet added to the CustomerId I want to ignore them.
I have a linq query that is working like I want
var query = from t in ctx.PurchaseTable
join j in ctx.CustomerTable on t.CustomerId equals
j.ConsumerId
where j.AllowEmails==true
group t by new
{
t.CustomerId,
j.ConsumerName,
j.EmailAddress
}
into g
select new {Customer = g.Key};
Now I could just do a foreach loop and add the results into a list however I think it would be nice to add to the list as part of the query.
This is what I have got so far.
var data = (from t in ctx.PurchaseTable
join j in ctx.CustomerTable on t.CustomerId equals
j.CustomerId
where j.AllowEmails== true
//group t by new //group t by new ConsumerModel
group t by new CustomerModel
{
CustomerName= t.CustomerName,
Email= j.EmailAddress,
CustomerId = j.CustomerId
}
into g select g);
Can anyone point me in the right direction to fix my query?
Thanks for your help!
You need to select g.Key.
g is an IGrouping<CustomerModel, Purchase> that includes the elements in the group.

Categories