LINQ Query Variable passed to Another LINQ Query - linq

What is the difference between the query in this post:
Save LINQ Query As Variable To Call Another LINQ Query
var parentLoc = (from a in db.PartsLocations
where a.LocationName == aContainer
select a.ParentLocation);
var locations = (from b in db.PartsLocations
where b.LocationID == parentLoc
select b).ToList();
to the following example from this post.
Dim persVogel = From p In db.People
Where p.LastName = "Vogel"
Select p
Dim persVogelPHVIS = From pp In persVogel
Where pp.Company.Name = "PHVIS"
Select pp
Both of these have declared 2 queries and use the first query variable into second query.
What is the reason to use Single() in the first example but was not used in visualstudiomagazine.com article? Thanks

The two samples are fundamentally different.
First Sample
I think you pasted this one incorrectly...from the referenced question, the query should be:
var parentLoc = (from a in db.PartsLocations
where a.LocationName == aContainer
select a.ParentLocation).Single();
var locations = (from b in db.PartsLocations
where b.LocationID == parentLoc
select b).ToList();
(I am going to assume that LocationID and ParentLocation are typed as int.)
In this sample parentLoc is an int - a single instance of a ParentLocation value, obtained from the PartsLocations table. So what you get is an int.
The second linq statement sources its records also from the PartsLocations table. It uses parentLoc to identify records within that table (e.g. where b.LocationID == parentLoc). What you get at the end is a set of PartsLocations records.
The .Single() call is made because you want to compare the result to LocationID in the second statement, and cannot compare int to IEnumerable<int>.
Second Sample
Dim persVogel = From p In db.People
Where p.LastName = "Vogel"
Select p
Dim persVogelPHVIS = From pp In persVogel
Where pp.Company.Name = "PHVIS"
Select pp
In the second sample, persVogel is a subset of records from the People table (specifically, the subset of people with LastName == "Vogel") - so what you get is a set of People records.
The second linq statement is based on this subset of records (From pp In persVogel) and further filters them down to records where pp.Company.Name = "PHVIS". What you get is still a set of People records.
These two statements could easily be compressed into one single statement:
Dim persVogelPHVIS = From p In db.People
Where p.LastName = "Vogel"
AndAlso p.Company.Name = "PHVIS"
Select p
You will still get a set of People records at the end.

Related

differences in LINQ queries

Can someone explain why, when a query should be returning one string item only like in the example below;
From c in context.Products Where c.Id=prodId Select c.Name
Why cant that be done like so;
Dim prodDeleted as String = (From c in context.Products Where c.Id=prodId Select c.Name).ToString()
bvecause it returns this (System.Data.Objects.ObjectQuery`1[System.String]) , instead of the product name
versus having to do it like so;
Dim prodDeleted = (From c In ctx.products
Where c.Id = prodId
Select c).FirstOrDefault()
Dim deletedprodname As String = prodDeleted.Name.ToString()
Because all calls to Select return an IEnumerable rather than a single element.
To verify that your query really returns a single element, you need to add the call to Single. Or, if you don't care if a single element or multiple elements were returned, you can grab the first using First.
If you're not against using the VB.NET equivalent of lambda syntax, you can streamline everything:
Dim deletedProdName As String =
ctx.products.SingleOrDefault(Function(c) c.Id = prodId).Name

Distinct works on IQueryable but not List<T>?? Why?

First Table is the View and Second is the result I want
This below query works fine
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new BTWStudents
{
StudentId = V.StudentId
Amount= V.PaymentMethod == "Cashier Check" ? V.Amount: "0.00"
}).Distinct().ToList();
But I changed it to List to add string formatting(see below)
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new {V}).ToList().Select(x => new BTWStudents
{
StudentId = V.StudentId
Amount= V.PaymentMethod == "Cashier Check" ? String.Format("{0:c}",V.Amount): "0.00"
}).Distinct().ToList();
With this Second Query I get this
Why is distinct not working in the second query?
When working with objects (in your case a wrapped anonymous type because you are using Select new {V} rather than just Select V), Distinct calls the object.Equals when doing the comparison. Internally, this checks the object's hash code. You'll find in this case, the hash code of the two objects is different even though the fields contain the same values. To fix this, you will need to override Equals on the object type or pass a custom IEqualityComparer implementation into the Distinct overload. You should be able to find a number of examples online searching for "Distinct IEqualityComparer".
Try this (moved your distinct to the first query and corrected your bugged if/then/else):
List<BTWStudents> students = (from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
select new {V}).Distinct().ToList().Select(x => new BTWStudents
{
classId = V.Class.HasValue ? V.Class.Value : 0,
studentName = V.StudentName,
paymentAmount = V.PaymentMethod == "Cashier Check" ? String.Format("{0:c}",x.V.AmountOwed): "0.00"
}).ToList();
You can get around using Distinct all together if you Group by StudentID
var studentsGroupedByPayment =
(from V in db.vwStudentCoursesSD
where classIds.Contains(V.Class.Value)
group V by V.StudentId into groupedV
select new
{
StudentID = groupedV.Key,
Amount = string.Format("{0:C}",
groupedV.First().PaymentMethod == "Cashier Check" ?
groupedV.First().Amount : 0.0)
}
).ToList();

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

Using .Contains within a linq query returning a SystemException

I am having some trouble with a linq query I am trying to write.
I have List A of products that have been modified so I am trying to get the list of products from the db to allow me to apply the changes to them.
I have tried 2 different queries
var query = from p in db.Products
where products.Select(z => z.id).Contains(p.Id)
select p;
var query2 = from p in db.Products where (from o in products
select o.id)
.Contains(p.Id)
select p;
Both attempts are returning an error
base {System.SystemException} = {"Unable to create a constant value of type 'ProjectABC.Models.ProductModel'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."}
What am I doing wrong?
I had the same problem the other day, seems EF doesn't support Select().Contains() without giving that error. After testing around for a bit, I ended up splitting it up in what in your case would correspond to;
var IDs = products.Select(z=>z.id);
var query = from p in db.Products
where IDs.Contains(p.Id)
select p;
which worked well in my case when the "products" collection was in memory anyway (ie a ToList()'ed result from the database)

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