Performing a sum subquery using linq - linq

Please could someone assist with the below query. I'm trying to select the Sum of all receipts per Client. But the 'Total =' sub query in my select section is not working and I'm getting the following error:
Unable to create a constant value of type 'AppName.Domain.Entities.AccountingEntry'. Only primitive types or enumeration types are supported in this context.
I've already tried doing a ToList() after that query but this results in the same problem. What is the standard way of selecting a Sum as a subquery using linq?
var receipts = (from ae in repo.AccountingEntries
join c in repo.Clients on ae.ClientId equals c.ClientId
join m in repo.Memberships on c.MembershipId equals m.MembershipId
where
(ae.EntryDate <= start) &&
(ae.ClientId != null) &&
(ae.AccountingEntryTypeId == (byte)Shared.AccountingEntryTypes.Receipt)
select new AppName.Reports.Clients.AgeAnalysis.Receipt
{
ClientId = (Guid)ae.ClientId,
Client = c.FirstName + " " + c.LastName,
Membership = c.Membership.Name,
Total = (from ae2 in repo.AccountingEntries where ae2.ClientId == ae.ClientId select ae2.Total).Sum()
});
Thanks,
Gary

This seems overly complex and unnecessary. If your entity model is set up properly, you can simplify by removing the joins and using a "group by" clause. Something along the lines of:
from ae in c.AccountingEntries
where
(ae.EntryDate <= start) &&
(ae.ClientId != null ) &&
(ae.AccountingEntryTypeId == (byte)Shared.AccountEntyrTypes.Receipt)
group by
ae.Client into g
select
new AppName.Reports.Clients.AgeAnalysis.Receipt
{
ClientId = (Guid)g.Key.ClientId,
Client = g.Key.FirstName + " " + g.Key.LastName,
Membership = g.Key.Membership.Name,
Total = g.Sum( p => p.Total )
}

Related

Expanding the Results View will enumerate the Enumerable

I am trying to write a LINQ statement using Entity Framework. I am getting an error stating "Expanding the Results View will enumerate the Enumerable"
My query is as follows :
IQueryable lis = (from que in _repo.Query<Question>()
where que.PresentationImageId == 1 join map in
_repo.Query<UserChildCourseQuestionMap>() on que.Id equals map.QuestionId into t
from rt in t.DefaultIfEmpty()
group t by que.Id
into g
select new
{
Id = g.Key,
QuestionBody = (from q in _repo.Query<Question>() where q.Id == g.Key select q.QuestionBody),
value = (from p in _repo.Query<UserChildCourseQuestionMap>()
where p.QuestionId == g.Key
select new
{
Name = gg.Key.AnswerOption,
Count = gg.Count(),
}).Union(from p in _repo.Query<UserChildCourseQuestionMap>()
where p.QuestionId == g.Key && p.UserInputText != null
group p by p.UserInputText into gg
select new
{
Name = gg.Key,
Count = gg.Count(),
}).Where(x => x.Name != null)
}
);
In LINQPad its working fine but in Visual Studio its not. Following is the image result which i am getting in LINQPad :
Please let me know where am I going wrong?
Following is the Screen Shot which i am getting when i expand the resultset:
Expand Image
The message " "Expanding the Results View will enumerate the Enumerable"" is not an error, it's a warning saying that if you expand the + sign the query will be run against the DDBB.
Just click in the + and expand the results tree, it should be ok.

How to find Distinct in more than one column in LINQ

I have a LINQ statement that returns many columns. I need to find distinct of unique combination of two columns. What is the best way to do this.
var productAttributeQuery =
from pa in ctx.exch_productattributeSet
join pp in ctx.exch_parentproductSet
on pa.exch_ParentProductId.Id equals pp.Id
join ep in ctx.exch_exchangeproductSet
on pp.exch_parentproductId equals ep.exch_ParentProductId.Id
where pa.exch_EffBeginDate <= effectiveDateForBeginCompare
&& pa.exch_EffEndDate >= effectiveDateForEndCompare
&& pa.statuscode == StusCodeEnum.Active
where pp.exch_EffBeginDate <= effectiveDateForBeginCompare
&& pp.exch_EffEndDate >= effectiveDateForEndCompare
&& pp.statuscode == StatusCodeEnum.Active
where ep.statuscode == StatusCodeEnum.Active
select new ProductAttributeDto
{
ParentProductId = pa.exch_ParentProductId.Id,
AttributeId = pa.exch_AttributeId.Id,
AttributeValue = pa.exch_Value,
AttributeRawValue = pa.exch_RawValue
};
return productAttributeQuery.ToList();
I want to get Distinct combination of ParentProductId and AttributeId from this list
You can group by anonymous type and select keys (they will be distinct)
var query = from p in productAttributeQuery
group p by new {
p.ParentProductId,
p.AttributeId
} into g
select g.Key;
You can use same approach with you original query if you want to get distinct pairs on server side.
Another approach - project results into pairs and get distinct from them:
var query = productAttributeQuery
.Select(p => new { p.ParentProductId, p.AttributeId })
.Distinct();

How to write this Linq Query in a better way to return the sum

I have one LINQ query. In that I need to do some calculations. Everything is fine except when null value found in the either one condition then simply it returns null for the whole condition. Can anyone tell me how can i return the some value even there is a null value found in the condition.
Code
var model =
(from q in db.Porders
select new porders()
{
Id = q.Id,
DetCount = (from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Id).Count(),
Amount = (from amtpord in db.Porders
where amtpord.Id == q.Id
select amtpord.Freight + amtpord.Misc - amtpord.Discount
).FirstOrDefault() +
(from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Copies * amtdet.EstUnitPrice
).Sum()
}).ToList();
I think the DefaultIfEmpty() method will be the solution here
var model =
from q in db.Porders
select new porders()
{
DetCount =
db.PoDetails.Count(amtdet => amtdet.PoId == q.Id),
Amount =
(from amtpord in db.Porders
where amtpord.Id == q.Id
select amtpord.Freight + amtpord.Misc - amtpord.Discount)
.DefaultIfEmpty().First()
+
(from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Copies * amtdet.EstUnitPrice)
.DefaultIfEmpty().Sum()
}
Try applying coalescing column ?? 0 operator on nullable columns or on the result of the FirstOrDefault (for the case that condition is not met). Linq to entities will turn this operator into SQL:
CASE WHEN Column IS NOT NULL THEN Column ELSE 0 END
It will look like:
var model =
(from q in db.Porders
select new porders()
{
Id = q.Id,
Amount = (from amtpord in db.Porders
where amtpord.Id == q.Id
select amtpord.Freight ?? 0 + amtpord.Misc ?? 0 - amtpord.Discount ?? 0
).FirstOrDefault() ?? 0 +
(from amtdet in db.PoDetails
where amtdet.PoId == q.Id
select amtdet.Copies ?? 0 * amtdet.EstUnitPrice ?? 0
).Sum() ?? 0
}).ToList();
Let me first assume that there is a navigation property Porder.Details. Next, why do you select the same Porder in a sub query? It seems to me that your query can be simplified as
from q in db.Porders
select new porders()
{
Id = q.Id,
DetCount = q.Details.Count(),
Amount = q.Freight + q.Misc - q.Discount
+ q.PoDetails.Select( d => d.Copies * d.EstUnitPrice)
.DefaultIfEmpty().Sum()
}
If there isn't such a navigation property it is highly recommended to create one. If you can't or don't want to do that for whatever reason, you should group join the detail records in the main query (db.Porders.GroupJoin(db.PoDetails...)).
If the null values are caused by Freight, Misc or Discount to be nullable, use ?? operator: q.Freight ?? 0.

How to get two sums from a linq query

Summary
I have a list of Transactions. Using Linq, I want to get a sum of the Cost and sum of the Quantity from this list in one query.
Grouping
My first thought is to use grouping - but I don't really have a key that I want to group on, I want just one group with the results from the whole list. So, I happen to have a property called "Parent" that will be the same for all of the transactions, so I'm using that to group on:
var totalCostQuery =
(from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
group t by t.Parent into g
select new
{
TotalCost = g.Sum(t => t.Cost.GetValueOrDefault()),
TotalQuantity = g.Sum(t => t.Quantity.GetValueOrDefault())
});
Grouping by t.Parent seems like it could be wrong. I really don't want to group at all, I just want the sum of t.Quantity and sum of t.Cost.
Is that the correct way to get a sum of two different properties or can it be done in a different way.
Assuming this is Linq to SQL or Entity Framework, you can do that:
var totalCostQuery =
(from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
group t by 1 into g
select new
{
TotalCost = g.Sum(t => t.Cost),
TotalQuantity = g.Sum(t => t.Quantity)
});
Note that you don't need to use GetValueOrDefault, null values will be ignored in the sum.
EDIT: not sure this works with Linq to NHibernate though...
Note that if you're using Linq to objects, the solution above won't be efficient, because it will enumerate each group twice (once for each sum). In that case you can use Aggregate instead:
var transactions =
from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
select t;
var total =
transactions.Aggregate(
new { TotalCost = 0.0, TotalQuantity = 0 },
(acc, t) =>
{
TotalCost = acc.TotalCost + t.Cost.GetValueOrDefault(),
TotalQuantity = acc.TotalQuantity + t.Quantity.GetValueOrDefault(),
});

How to do a simple Count in Linq?

I wanted to do a paging style table, but NeerDinner example fetches the entire data into a PaggingList type, and I have more than 10 000 rows to be fetched, so I skipped that part.
so I come up with this query
var r = (from p in db.Prizes
join c in db.Calendars on p.calendar_id equals c.calendar_id
join ch in db.Challenges on c.calendar_id equals ch.calendar_id
join ca in db.ChallengeAnswers on ch.challenge_id equals ca.challenge_id
join cr in db.ChallengeResponses on ca.challenge_answer_id equals cr.challenge_answer_id
where
p.prize_id.Equals(prizeId)
&& ch.day >= p.from_day && ch.day <= p.to_day
&& ca.correct.Equals(true)
&& ch.day.Equals(day)
orderby cr.Subscribers.name
select new PossibleWinner()
{
Name = cr.Subscribers.name,
Email = cr.Subscribers.email,
SubscriberId = cr.subscriber_id,
ChallengeDay = ch.day,
Question = ch.question,
Answer = ca.answer
})
.Skip(size * page)
.Take(size);
Problem is, how can I get the total number of results before the Take part?
I was thinking of:
var t = (from p in db.JK_Prizes
join c in db.JK_Calendars on p.calendar_id equals c.calendar_id
join ch in db.JK_Challenges on c.calendar_id equals ch.calendar_id
join ca in db.JK_ChallengeAnswers on ch.challenge_id equals ca.challenge_id
join cr in db.JK_ChallengeResponses on ca.challenge_answer_id equals cr.challenge_answer_id
where
p.prize_id.Equals(prizeId)
&& ch.day >= p.from_day && ch.day <= p.to_day
&& ca.correct.Equals(true)
&& ch.day.Equals(day)
select cr.subscriber_id)
.Count();
but that will do the query all over again...
anyone has suggestions on how can I do this effectively ?
If you take a query as such:
var qry = (from x in y
select x).Count();
...LINQ to SQL will be clever enough to make this a SELECT COUNT query, which is potentially rather efficient (efficiency will depend more on the conditions in the query). Bottom line is that the count operation happens in the database, not in LINQ code.
Writing my old comments :Well i was facing the same issue some time back and then i came up with LINQ to SP =). Make an SP and drop that into your entities and use it.you can get write Sp according to your need like pulling total record column too. It is more easy and fast as compare to that whet you are using wright now.
You can put count for query logic as well as, see the sample as below:
public int GetTotalCountForAllEmployeesByReportsTo(int? reportsTo, string orderBy = default(string), int startRowIndex = default(int), int maximumRows = default(int))
{
//Validate Input
if (reportsTo.IsEmpty())
return GetTotalCountForAllEmployees(orderBy, startRowIndex, maximumRows);
return _DatabaseContext.Employees.Count(employee => reportsTo == null ? employee.ReportsTo == null : employee.ReportsTo == reportsTo);
}

Resources