I am having following linq -
var quantity = (from p in context.StoreInventory
where p.BookId== BookId
&& p.StoreAddress == StoreAddress
select p).Sum(i => i.Quantity);
I am getting error -
The method 'Sum' is not supported
Can anyone tell me the reason and required changes.
var quantity = (from p in context.StoreInventory
where p.BookId== BookId
&& p.StoreAddress == StoreAddress
select p.Quantity).Sum();
This should work - the sum is performed on 'Quality' column, which is taken using select statement. That's because Sum(expression) is not supported by LINQ to Entities, but standard Sum() is.
Whole work should be done by database, so no rows will be retrieved by application - just single number.
Use Enumerable.ToList before you call Sum to convert the query to collection.
var quantity = (from p in context.StoreInventory
where p.BookId== BookId
&& p.StoreAddress == StoreAddress
select p).ToList().Sum(i => i.Quantity);
Edit: This will bring all the row and will apply the sum which is not efficient way of doing. As you need to sum up quantity you can select quanity instead of row.
var quantity = (from p in context.StoreInventory
where p.BookId== BookId
&& p.StoreAddress == StoreAddress
select p.Quantity).Sum();
Related
I have table Order and OrderItem. Now, I need to get all order items for a range of orders (For example, order for the entire month). The order and order item itself has many columns. So, using Include("OrderItem") is amazingly slow.
The number of record of orders is around 20K record per month with order items are around 50K-60K records.
Since it is a range of date (eg. daily, weekly, monthly, yearly, etc...) currently, I am doing 2 selects.
var orders = (from rec in Orders.AsNoTracking()
where (rec.OrderDate >= startDate) && (rec.OrderDate <= endDate)
orderby rec.OrderDate descending
select rec).ToList();
var orderItems = (from rec in OrderItems.AsNoTracking()
join recOrder in Orders.AsNoTracking() on new { rec.LocationId, rec.StoreId, rec.OrderId } equals new { recOrder.LocationId, recOrder.StoreId, recOrder.OrderId }
orderby recOrder.OrderDate descending
where (recOrder.OrderDate >= startDate) && (recOrder.OrderDate <= endDate)
select rec).ToList();
This is all good. However, when I do paging (1 page can display 25 - 1000 records per page depending on user preferences), I am thinking to get away from 2 selects and use union or predicate (using PredicateBuilder in LinqKit), something like this:
var orders = (from rec in Orders.AsNoTracking()
where (rec.OrderDate >= startDate) && (rec.OrderDate <= endDate)
orderby rec.OrderDate descending
select rec).Skip(page * recPerPage).Take(recPerPage).ToList();
Now, to get the order items, I propose to use 3 options. Please let me know which one is better for small records (25 - 1000 records per page).
Option #1: Use another select with Skip and Take for order items.
Option #2: Use Union.
IQueryable<OrderItem> queries = null;
foreach (Tuple<int, int, int> key in orderIds)
{
int locationId = key.Item1, storeId = key.Item2, orderId = key.Item3;
var recs = (from rec in OrderItems.AsNoTracking()
where (rec.LocationId == locationId) && (rec.StoreId == storeId) && (rec.OrderId == orderId)
select rec);
queries = (queries == null) ? recs : queries.Union(recs);
}
var orderItems = queries.ToList();
Option #3: Use PredicateBuilder.
var predicate = PredicateBuilder.New<OrderItem>();
foreach (Tuple<int, int, int> key in orderIds)
{
int locationId = key.Item1, storeId = key.Item2, orderId = key.Item3;
predicate = predicate.Or(rec => (rec.LocationId == locationId) && (rec.StoreId == storeId) && (rec.OrderId == orderId));
}
var orderItems = OrderItems.AsNoTracking().AsExpandable().Where(predicate).ToList();
I prefer to use Union or PredicateBuilder so to get order items the function doesn't have to know if the orders were selected using Date Range OR search by product OR search by customer OR any other future search options. All OrderItem need to know is the list of order ids.
So, my question is, in term of speed and performance, which option is the best option?
NOTE:
If I tried to get 1000 records, sometimes Union and PredicateBuilder will throw StackOverflowException. So, I limit it to 500 records. If user preference is 1000 records, then, I do 2 calls.
I also tried to use LINQPad to look at SQL generated by predicate builder, but it couldn't recognize AsExpandable() (Yes, I have included LinqKit DLL). So, no luck here.
Please help.
Thanks.
I'm trying to get a list of students based on their status, grouped by their college.
So I have three tables, Students and Colleges. Each student record has a status, that can be 'Prospect', 'Accepted' or 'WebApp'. What I need to do is get a list of students based on the status selected and then display the College's name, along with the number of students that go to that college and have their status set to the status passed in. I think this needs to be an aggregate query, since the counts are coming from the string Status field.
I'm not sure how to do this in MS SQL, since the count is coming from the same table and it's based on the status field's value.
Here is the start of my query, which takes in the search parameters, but I can't figure out how to filter on the status to return the counts.
SELECT Colleges.Name, [Status], Count([Status])
FROM Students
JOIN Colleges ON Students.UniversityId = Colleges.id OR Students.+College = Colleges.Name
GROUP BY Students.[Status], Colleges.Name
ORDER BY Colleges.Name;
Accepts = Status('Accepted')
WebApps = Status('WebApp')
Total = Sum(Accpets + WebApps)
Select
Colleges.Name,
SUM(Case when Students.Status like 'Accepted' then 1 else 0 end) Accepts,
SUM(Case when Students.Status like 'WebApp' then 1 else 0 end) WebApps,
COUNT(*) Total
from Students
join Colleges on Students.UniversityId = Colleges.Id OR Students.CurrentCollege = Colleges.Name
Group by Colleges.Name
The LINQ:
var results =
(from c in db.Colleges // db is your DataContext
select new
{
CollegeName = c.Name,
AcceptedStatus = db.Students.Count(r => r.Status.ToUpper() == "ACCEPTED" && (r.UniversityId == c.Id || r.CurrentCollege == c.Name)),
WebAppStatus = db.Students.Count(r => r.Status.ToUpper() == "WEBAPP" && (r.UniversityId== c.Id || r.CurrentCollege == c.Name)),
Total = db.Students.Count(s => s.UniversityId == c.Id || s.CurrentCollege == c.Name)
}).ToList();
Try this http://www.linqpad.net/
Its free and you can convert the linq to sql queries
I've tried to write a LINQ query that will give me all the details in one place, I need the date of production, the employee name and the sum of money this employee should get for his work. this is what I have so far:
var PrePerWorker =
(from Production in context.production
where Production.ProductionDate >= dtpStartDate.SelectedDate && Production.ProductionDate <= dtpEndDate.SelectedDate
select new
{
Worker =
(from Employee in context.employees
where Employee.ID == Production.EmpID
select Employee.FirstName).FirstOrDefault(),
DateOfProduction = Production.ProductionDate,
Total =
Production.Side == 1 ? Production.Amount *
(from Product in context.products
where Product.ProductID == Production.ProductID
select Product.SideA).FirstOrDefault():
Production.Side == 2 ? Production.Amount *
(from Product in context.products
where Product.ProductID == Production.ProductID
select Product.SideB).FirstOrDefault():
Production.Side == 3 ? Production.Amount *
(from Product in context.products
where Product.ProductID == Production.ProductID
select Product.SideC).FirstOrDefault(): 0
}).GroupBy(x => x.DateOfProduction, x => x.Worker);
When I run this and then try to iterate over the results I get an error saying "Specified method is not supported".
Anyone knows why? and how can I fix this?
My guess is that the tertiary ? : operator can't be translated to SQL
For grouping by 2 columns you need GroupBy(x => new {x.DateOfProduction, x.Worker});. And can you explain what you need, because your linq looks like so hard for me.
I just want the apartment complex count along with the other values. Only adding the count breaks the code. The error I get is "Sequence operators not supported for type 'System.String'." I have also tried changing apartCount to an int with no luck. Any help would be appreciated
using (var db = new DataClasses2DataContext())
{
var zips = (from s in db.ZipCodeServiceAvailabilities
join b in db.ZipCodeBoundaries on s.ZipCode equals b.ZipCode
join a in db.pdx_apart_views on s.ZipCode equals a.Zip_Code
where (s.IsServiced == 1 && b.Ordering % 10 == 0)
orderby b.ZipCode
select new
{
zipCode = b.ZipCode.Trim(),
latitude = b.Latitude,
longitude = b.Longitude,
apartCount = a.Apartment_complex.Count()
}).ToArray();
}
I think you miss group by clause in your query.
or you can use corolated sub query in select clause. please explain your question more
I'm trying to rewrite a SQL query in LINQ to Entities. I'm using LINQPad with a typed datacontext from my own assembly to test things out.
The SQL query I'm trying to rewrite:
SELECT DISTINCT variantID AS setID, option_value AS name, option_value_description AS description, sort_order as sortOrder
FROM all_products_option_names AS lst
WHERE lst.optionID=14 AND lst.productID IN (SELECT productID FROM all_products_option_names
WHERE optionID=7 AND option_value IN (SELECT name FROM brands
WHERE brandID=1))
ORDER BY sortOrder;
The LINQ to Entities query I've come up with so far (which doesn't work due to a timeout error):
from a in all_products_option_names
where a.optionID == 14 && all_products_option_names.Any(x => x.productID == a.productID && x.optionID == 7 && brands.Any(y => y.name == x.option_value && y.brandID == 1))
select new
{
id = a.variantID,
name = a.option_value,
description = a.option_value_description,
sortOrder = a.sort_order,
}
This is the error I get when I run the above query: An error occurred while executing the command definition. See the inner exception for details.
And the inner exception is: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Edit:
I use MySQL and probably that's why LINQPad doesn't show me the generated SQL.
The SQL version doesn't time out.
Edit 2:
I solved the problem by completely changing the query, so this question is irrelevant now.
I marked Steven's response as the correct one, because he was closest to what i was trying to achieve and his response gave me the idea which led me to the solution.
Try this:
var brandNames =
from brand in db.Brands
where brand.ID == 1
select name;
var brandProductNames =
from p in db.all_products_option_names
where p.optionID == 7
where brandNames.Contains(p.option_value)
select p.productId;
var results =
from p in db.all_products_option_names
where p.optionID == 14
where brandProductNames.Contains(p.productId)
select new
{
setID = p.variantID,
name = p.option_value,
description = p.option_value_description,
sortOrder = p.sort_order
};
I would recommend doing joins rather than sub-select's as you have them. Sub-selects are not very efficient when you look at performance, it's like having loops inside of loops when you code , not a good idea. This could actually cause that timeout your getting if your database is running slowly even thou that looks like a simple query.
I would try using joins with a distinct at the end like this:
var results =
(from p in db.all_products_option_names
join p2 in db.all_products_option_names on p.productId equals p2.productId
join b in db.Brands on p2.option_value equals b.name
where p.optionID == 14
where p2.optionID == 7
where b.BrandID == 1
select new
{
setID = p.variantID,
name = p.option_value,
description = p.option_value_description,
sortOrder = p.sort_order
}).Distinct();
Or you could try using joins with the into and with an any like so
var results =
from p in db.all_products_option_names
join p2 in (from p3 in db.all_products_option_names.Where(x => x.optionId == 7)
join b in db.Brands.Where(x => x.BrandID == 1) on p3.option_value equals b.name
select p3) into pg
where p.optionID == 14
where pg.Any()
select new
{
setID = p.variantID,
name = p.option_value,
description = p.option_value_description,
sortOrder = p.sort_order
};