How to do a simple Count in Linq? - 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);
}

Related

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();

LINQ to Entities three table join query

I'm having a bit trouble with a query in Linq to Entities which I hope someone can shed a light on :-) What I'm trying to do is to create a query that joins three tables.
So far it works, but since the last table I'm trying to join is empty, the result of the query doesn't contain any records. When I remove the last join, it gives me the right results.
My query looks like this:
var query = from p in db.QuizParticipants
join points in db.ParticipantPoints on p.id
equals points.participantId into participantsGroup
from po in participantsGroup
join winners in db.Winners on p.id
equals winners.participantId into winnersGroup
from w in winnersGroup
where p.hasAttended == 1 && p.weeknumber == weeknumber
select new
{
ParticipantId = p.id,
HasAttended = p.hasAttended,
Weeknumber = p.weeknumber,
UmbracoMemberId = p.umbMemberId,
Points = po.points,
HasWonFirstPrize = w.hasWonFirstPrize,
HasWonVoucher = w.hasWonVoucher
};
What I would like is to get some records even if the Winners table is empty or there is no match in it.
Any help/hint on this is greatly appreciated! :-)
Thanks a lot in advance.
/ Bo
If you set these up as related entities instead of doing joins, I think it will be easier to do what you're trying to do.
var query = from p in db.QuizParticipants
where p.hasAttended == 1 && p.weeknumber == weeknumber
select new
{
ParticipantId = p.id,
HasAttended = p.hasAttended,
Weeknumber = p.weeknumber,
UmbracoMemberId = p.umbMemberId,
Points = p.ParticipantPoints.Sum(pts => pts.points),
HasWonFirstPrize = p.Winners.Any(w => w.hasWonFirstPrize),
HasWonVoucher = p.Winners.Any(w => w.hasWonVoucher)
};
This is assuming hasWonFirstPrize and hasWonVoucher are boolean fields, but you can use any aggregate function to get the results you need, such as p.Winners.Any(w => w.hasWonFirstPrize == 1)
I don't use query syntax a lot but I believe you need to change from w in winnersGroup to from w in winnersGroup.DefaultIfEmpty()

Greater Than Condition in Linq Join

I had tried to join two table conditionally but it is giving me syntax error. I tried to find solution in the net but i cannot find how to do conditional join with condition. The only other alternative is to get the value first from one table and make a query again.
I just want to confirm if there is any other way to do conditional join with linq.
Here is my code, I am trying to find all position that is equal or lower than me. Basically I want to get my peers and subordinates.
from e in entity.M_Employee
join p in entity.M_Position on e.PostionId >= p.PositionId
select p;
You can't do that with a LINQ joins - LINQ only supports equijoins. However, you can do this:
var query = from e in entity.M_Employee
from p in entity.M_Position
where e.PostionId >= p.PositionId
select p;
Or a slightly alternative but equivalent approach:
var query = entity.M_Employee
.SelectMany(e => entity.M_Position
.Where(p => e.PostionId >= p.PositionId));
Following:
from e in entity.M_Employee
from p in entity.M_Position.Where(p => e.PostionId >= p.PositionId)
select p;
will produce exactly the same SQL you are after (INNER JOIN Position P ON E..PostionId >= P.PositionId).
var currentDetails = from c in customers
group c by new { c.Name, c.Authed } into g
where g.Key.Authed == "True"
select g.OrderByDescending(t => t.EffectiveDate).First();
var currentAndUnauthorised = (from c in customers
join cd in currentDetails
on c.Name equals cd.Name
where c.EffectiveDate >= cd.EffectiveDate
select c).OrderBy(o => o.CoverId).ThenBy(o => o.EffectiveDate);
If you have a table of historic detail changes including authorisation status and effective date. The first query finds each customers current details and the second query adds all subsequent unauthorised detail changes in the table.
Hope this is helpful as it took me some time and help to get too.

Aggregate functions with a left outer join in LINQ to Entities

I've been looking through related LINQ questions here trying to figure this one out, but I'm having some trouble converting a SQL query of mine to the equivalent LINQ to Entities version.
select companies.CommpanyName,
job.Position,
count(offers.jobID) As Offered,
job.Openings,
job.Filled
from jobs
left outer join offers on jobs.ID = offers.JobID
join membership.dbo.individuals on jobs.UserID = individuals.ID
join membership.dbo.companies on individuals.CompanyID = companies.ID
where jobs.Hidden = 0
group by offers.JobID,
companies.CommpanyName,
job.Position,
job.Openings,
job.Filled
I've done left outer joins in LINQ before similar to this example but I'm not sure how to combine the count and group statements with this to get the desired result:
CompanyName Position Offered Openings Filled
1 Exmaple Co. Job X 0 2 0
2 Example Co. Job Y 4 6 3
3 Test Co. Job Z 1 1 1
The query is further complicated by the fact that it needs to utilize two separate data contexts. I apologize for the lack of example code, but I'm really not sure how to start this, my LINQ-fu is still weak.
Update:
This is the solution I arrived at with Craig's help, had to use LINQ to Objects because of the unfortunate multiple context setup, JobWithOfferCounts is not an entity object:
IEnumerable<Job> t = context1.JobSet.Include("Offers").Include("Contacts").Where(j => j.Hidden == false);
IEnumerable <JobWithOfferCounts> r = (from j in t
join i in context2.IndividualSet on j.UserID equals i.ID
join c in context2.CompanySet on i.CompanyID equals c.ID
select new JobWithOfferCounts()
{
JobObject = j,
CompanyID = Convert.ToInt32(c.ID),
CompanyName = c.HostName,
OfferCount = j.offers.Count(o => o.Rejected == false),
FilledCount = j.offers.Count(o => o.Accepted == true),
PendingCount = j.offers.Count(o => o.Accepted == false && o.Rejected == false)
});
return r;
I can't see why you have individuals in your query, or why you group by offers.JobID when it (unlike jobs.JobId) could be null, but here's a first stab:
var q = from c in Context.Companies
from i in c.Individuals
from j in i.Jobs
where j.Hidden == 0
select new
{
CompanyName = c.CompanyName,
Position = j.Position,
Offered = j.Offers.Count(),
Openings = j.Openings,
Filled = j.Filled
};
It's rarely correct to use join in LINQ to Entities or LINQ to SQL.

SubSonic3 linq problem

I have this query:
var rights = from gu in db.GroupUsers
join g in db.Groups on gu.GroupId equals g.GroupId
join gr in db.GroupRights on g.GroupId equals gr.GroupId
join r in db.Rights on gr.RightId equals r.RightId
where gu.UserId == userId && g.IsDeleted == false
select r;
It gets translated to:
SELECT [t0].[Name] AS Name1, [t0].[RightId] AS RightId1
FROM [dbo].[GroupUsers] AS t1
INNER JOIN [dbo].[Groups] AS t2
ON ([t1].[GroupId] = [t2].[GroupId])
INNER JOIN [dbo].[GroupRights] AS t3
ON ([t2].[GroupId] = [t3].[GroupId])
INNER JOIN [dbo].[Rights] AS t0
ON ([t3].[RightId] = [t0].[RightId])
WHERE (([t1].[UserId] = 3345) AND ([t2].[IsDeleted] = 0))
This is still ok, but in .NET my SubSonic objects are all empty. So the query returns 15 objects, but Name and RightId are an empty string and -1.
Can this have anything to do with the fact that Name is returned as Name1 and RightId is returned as RightId1?
I'll have a look into the source code of SubSonic3 to find something.
SubSonic3 Source Code: the query does get translated to the sql above. Because of the Name1 and RightId1, the Load in Database.cs doesn't work properly. The line :
currentProp = cachedProps.SingleOrDefault
(x => x.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase));
doesn't find the currentProp because the currentProp is Name (and RightId) and not Name1 and RightId1. Well, fixing this won't be for today. Maybe someone from SubSonic3 can have a look at this, because it's pretty annoying. I could write a sort of hack into the source code, but it won't be pretty. I guess the translation should be cleaned up so that Name1 and RightId1 are translated back to Name and RightId.
In TSqlFormatter.cs there's next line that adds these AS strings
(in method :
protected override Expression VisitSelect(SelectExpression select)
{
...
if (!string.IsNullOrEmpty(column.Name) && (c == null || c.Name != column.Name))
{
sb.Append(" AS ");
sb.Append(column.Name);
}
...
}
If I put the two Appends in comment, then my linq query does work and I do get the right data. But I guess those two lines are there for a reason, but what reason? In which usecase are the two lines necessary?

Resources