I'm trying to use paging in conjunction with a sum projection to get a sum of the values in a column for just the page of results I'm interested in. I'm using .NET, C# and NHibernate 3.1
I have an ICriteria to start with which is related to all rows from the associated db table.
I'm then doing the following to get a version with the first page (say, 10 items out of 40):
ICriteria recordsCriteria = CriteriaTransformer.Clone(criteria);
recordsCriteria.SetFirstResult(0);
recordsCriteria.SetMaxResults(10);
I'm using this ICriteria for something else so I then create two further clones:
ICriteria totalAggCriteria = CriteriaTransformer.Clone(criteria);
ICriteria pageAggCriteria = CriteriaTransformer.Clone(recordsCriteria);
If I take a look inside these two new ones the first has 40 items in and the second has 10 - exactly what I want.
Let's say the objects coming back from the DB have a column called "ColA" and it's of type Int32.
From this, I want the sum of all 40 ColA values and the sum of the first 10 ColA values.
To get the sum of all 40 ColA values, I do the following:
totalAggCriteria.SetProjection(NHibernate.Criterion.Projections.Sum("ColA"));
var totalSum = totalAggCriteria.UniqueResult();
The value in totalSum is correct.
To get the sum of the first 10 ColA values, I'm trying the following:
pageAggCriteria.SetProjection(NHibernate.Criterion.Projections.Sum("ColA"));
vat pageSum = pageAddCriteria.UniqueResult();
However, this gives me the same value as the previous one - for all 40 ColA values.
I've also tried the following but it gives the same result:
pageAggCriteria.SetProjection(NHibernate.Criterion.Projections.Sum(column));
pageAggCriteria.SetFirstResult(firstResult.Value);
pageAggCriteria.SetMaxResults(pageSize.Value);
pageSum = pageAggCriteria.UniqueResult();
And also:
pageAggCriteria.SetFirstResult(firstResult.Value);
pageAggCriteria.SetMaxResults(pageSize.Value);
pageAggCriteria.SetProjection(NHibernate.Criterion.Projections.Sum(column));
pageSum = pageAggCriteria.UniqueResult();
Can anyone give an idea on where I'm going wrong and how I can actually get the sum of the ColA values in the first 10 results?
Thanks
Probably easiest to do that sum client side. The aggregate function is operating on the whole table. What you are trying to do is run the aggregate function against the paged result which I don't think is possible with NH.
In other words, you want select sum(colA) from (select top 10 ...) but that criteria will give you select top 10 sum(colA) from ...)
Related
I would like to know if its possible to do mathematical operation (e.g. Sum ) in sitecore fast query or any other way.
I have 100s of items with field 'Money spend' data type 'Integer'. I want to know the fast way to calculate the sum of this field for a specific person/user.
Here is what I am doing, I am using fast query to get the items and then calculating the sum.
var searchStr = "{30218229-CFA8-4BC3-9F01-01E3E6469E51}";
var query = string.Format("fast:/sitecore/content/Intranet/User/Detail/*[#Active ='1']//*[#Profile Id=\"%{0}%\"]", searchStr);
var items = Sitecore.Context.Database.SelectItems(query);
//Calculate sum
var sum = items.Aggregate(0, (x, y) => x + GeneralHelper.ConvertToInt16(y["Money spend"]));
I want to know how I can make the sum calculation process fast?
I think the best way is to use indexes (as Mark already mentioned):
create a custom index for your users and include your "money spend" value in it (and also the 'active' and 'profile id' as you are querying on those). Make sure the "money spend" is "stored".
create a custom class deriving from SearchResultItem to include the "money spend" field as a property
use the contentsearch api to query your users as you did with the fast query (index will be faster) and use your custom class that you just created to gather the results
use Linq to calculate what you need
The following nested line gives an error but I don't really understand what is wrong. I'm coding in C#. If I look at other examples this should do the trick but unfortunately it doesn't.
var PupilsAmount= entities.Reservation.AsEnumerable().Where(x => x.AmountOfAttendants= 2.Sum(x => x.PupilsAmount));
So I want to give the sum of the value PupilsAmount only for the records where the attendants amount = 2.
Thanks in advance!
The error message is because you're calling Sum on the value 2. Sum is an extension method that operates on IEnumerable<T> (e.g. some sort of collection), not on an int.
Based on your edit, what you're after is:
var PupilsAmount= entities.Reservation.AsEnumerable().Where(x=>x.AmountOfAttendants==2).Sum(x=>x.PupilsAmount);
What's happening in my modification is a two-stage process:
First, I filter the list using Where, to get only the records where AmountOfAttendants is equal to 2
Then, I sum PupilsAmount for the remaining records.
I'm using Linq/EF4.1 to pull some results from a database and would like to limit the results to the (X) most recent results. Where X is a number set by the user.
Is there a way to do this?
I'm currently passing them back as a List if this will help with limiting the result set. While I can limit this by looping until I hit X I'd just assume not pass the extra data around.
Just in case it is relevant...
C# MVC3 project running from a SQL Server database.
Use the Take function
int numberOfrecords=10; // read from user
listOfItems.OrderByDescending(x => x.CreatedDate).Take(numberOfrecords)
Assuming listOfItems is List of your entity objects and CreatedDate is a field which has the date created value (used here to do the Order by descending to get recent items).
Take() Function returns a specified number of contiguous elements from the start of a
sequence.
http://msdn.microsoft.com/en-us/library/bb503062.aspx
results = results.OrderByDescending(x=>x.Date).Take(10);
The OrderByDescending(...) will sort items by your date/time property (or w/e logic you want to use to get most recent) and Take(...) will limit to first x items (first being most recent, thanks to the ordering).
Edit: To return some rows not starting at the first row, use Skip():
results = results.OrderByDescending(x=>x.Date).Skip(50).Take(10);
Use Take(), before converting to a List. This way EF can optimize the query it creates and only return the data you need.
I have a sql table called expenses with an int column called cost. In my application this data is displayed on a grid which is refreshing every time I insert a new row with a linq2sql insert. What I would like to do is have an integer variable in my application that is the sum of all the fields in the cost column every time I insert a row.
Is there a simple way to sum these fields with linq2sql every time I do an insert. Please try to avoid lambda as I haven't gotten to learning that yet.
Thanks!
Assuming that you use query syntax instead of lambdas, here you are:
var totalCost = (from expensesRow in dataContext.Expenses
select expensesRow.cost)
.Sum();
Which in fact is the same as:
var totalCost = dataContext.Expenses
.Sum(x => x.cost);
Here dataContext is an instance of your Linq2Sql DataContext class.
You get to learn lambdas today. http://www.theabsentmindedcoder.com/2010/06/linq-sum.html has exactly what you want, and uses a very simple lambda to get there. You could get away without the lambda by making your select gather up only the one column of integers you're trying to sum, but why do extra work to not learn things?
Say I had a table called users with the following structure:
[Table users] - id | username | points_awarded
Then, I can find the total number of points I awarded every user by running the query:
SELECT SUM(points_awarded) as total_points FROM users
You can also count how many users have points greater than our equal to N. For example, says N = 500, then I can run:
SELECT COUNT(id) as num_users_with_points FROM users WHERE points_award >= 500
Check out:
http://dev.mysql.com/doc/refman/5.1/en/counting-rows.html
http://dev.mysql.com/doc/refman/5.0/en/func-op-summary-ref.html
for more information.
Is it possible to return a single value and an enumerable collection using LINQ to SQL?
The problem is, I'm trying to do paging across a large recordset. I only want to return 10 rows at a time so I'm using .Skip(20).Take(10) approach.
However I need to know the total number of records so I can show an appropriate page x of y.
Trying to avoid two separate queries.
Thanks
Don't be afraid of queries. Do both.
I came across this exact same issue and ended up with
var q = from i in tableName select i;
int total = q.Count();
foreach(var obj in q.Skip(20).Take(10))
{
...
}
It really wasn't a problem at all