returning values with a where clause - linq

I have two tables as follows:
ScholarSubject
ScholarSubjectID<pk>
ScholarID
SubjectID
Mark
and
AdmissionReq
SubjectID
DegreeCode
MinumumMark
I'm trying to return everything from a Degree table (with PK degreeID) where the mark for a scholar is less than the minimum mark for admissions. My query is as follows:
public List<object> getDegreeByAPSandRequirements()
{
using (DataLayer.CareerDatabaseEntities context = new DataLayer.CareerDatabaseEntities())
{
return (from Degrees in context.Degrees
join admissions in context.AdmissionReqs on
Degrees.DegreeCode equals admissions.DegreeCode
join subject in context.Subjects on
admissions.SubjectID equals subject.SubjectID
join scholarsubject in context.ScholarSubjects on
subject.SubjectID equals scholarsubject.SubjectID
join scholar in context.Scholars on
scholarsubject.ScholarID equals scholar.ScholarID
where Degrees.APSScore <= scholar.APSScore && admissions.MinimumMark <= scholarsubject.NSC && scholarsubject.SubjectID.Equals(admissions.SubjectID)
select Degrees).Distinct().ToList<object>();
}
}
Everything works, except if I change one of the marks (in ScholarSubject) to a lesser value than the minumum mark (in AdmissionsReq) then it still returns a degree. I want to return a degree if both marks are greater than the minimum requirements and not only one of the marks.
What am I doing wrong? Can someone please help me??

I'm still not sure I understand what you're trying to do - unless you have just one scholar in your database it seems to me you will return a list of all degrees achieved by all scholars. If you don't want this, you need to filter on scholarID in the where clause.
But anyway - in order to get more information I would try to do 2 things.
I would change your query and start it with the scholar not with the degree as this might avoid some duplicates:
from scholar in context.Scholars
join scholarsubject in context.ScholarSubjects on scholar.ScholarID equals scholarsubject.ScholarID
join subject in context.Subjects on scholarsubject.SubjectID equals subject.SubjectID
join admission in context.AdmissionReqs on subject.SubjectID equals admission.SubjectID
join degree in context.Degrees on admission.DegreeCode equals degree.DegreeCode
where degree.APSScore <= scholar.APSScore
&& admission.MinimumMark <= scholarsubject.NSC
//&& scholarsubject.SubjectID.Equals(admission.SubjectID) // you should not need this line as you have the joins in place to assert this
select degree)
.Distinct()
.ToList<object>();
If this produces the same result as your previous query, then I'd change the return type to see what exactly you are getting - replace the last line with this and inspect the collection:
select new {ScholarID = scholar.ScholarID, Degree = degree})
.Distinct()
.ToList();

Related

What tools are there that help build expression trees for dynamic LINQ queries?

My project needs to let users build their own dynamic queries. From what I've read, Expression Trees are the way to go. However the syntax is rather complicated.
I envision having a GUI where users would be able to check tables, select columns, specify parameters,etc and then build a string such as:
var myQuery =
from P in context.Projects
join UA in context.UserAttributes on P.ProjectID equals UA.ProjectID
join UBA in context.UserBooleanAttributes on UA.UserAttributeID equals UBA.UserAttributeID
join U in context.Users on UBA.UserID equals U.UserID
where P.ProjectID == 1
where UBA.Value == true
where (UA.UserAttributeID == 1 || UA.UserAttributeID == 2)
select new { uba = U };
And store that in a queries table. To process the query, I was hoping there is some library out there that will magically do something like:
var result = magic(str);
foreach(var user in result)
Foo(user.Email);
In this example I know that all my queries would return Users, but for other queries I would probably have to use reflection or in another column specify the expected type in results.
I found one project called LinqTextQueryBuilder which looks interesting, but I wanted to see if there are other alternatives.

linq query grouping and joining getting incorrect sum

I have the following code which is grouping and summing some values.
The sum "TotalCost" value is correct, however, when i uncomment the lines the sum value is wrong (its less than it should be)
Im doing something wrong, but cant figure this out. any ideas?
from orderItem in Order_ProductItem
//join ho in Hardware_Items on orderItem.OuterColour equals ho.Index
//join hi in Hardware_Items on orderItem.InnerColour equals hi.Index
where orderItem.SalesOrderID == 3272 && (orderItem.IsDeleted==null || orderItem.IsDeleted.Value == false)
group new { orderItem/*, hi, ho*/} by orderItem.FrameNo into grp
select new OrderItemModel
{
FrameNo = grp.Key,
TotalCost = grp.Sum(x => x.orderItem.SellingPrice),
//InternalColor = grp.FirstOrDefault().hi.Name,
//ExternalColor = grp.FirstOrDefault().ho.Name,
Quantity = grp.FirstOrDefault().orderItem.Quantity,
}
Basic Schema
Order_ProductItem
FrameNo
OuterColour
InnerColour
SellingPrice
Hardware_Items
Index
Name
The Order_ProductItem has FrameNo which is listed multiple times in the table, so im trying to get it to group them, then sum the SellingPrice of each row that has the same FrameNo.
If i exclude the bit to obtain colour (internal and external) the sum is correct.
In that case how can i also include the inner and outer color names?
You probably need to use a left join, because the inner join is filtering out some of your data. Here is an example on how you would change your first join.
join ho in Hardware_Items on orderItem.OuterColour equals ho.Index into hog
from ho in hog.DefaultIfEmpty()

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

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.

Stuck on a subquery that is grouping, in Linq`

I have some Linq code and it's working fine. It's a query that has a subquery in the Where clause. This subquery is doing a groupby. Works great.
The problem is that I don't know how to grab one of the results from the subquery out of the subquery into the parent.
Frst, here's the code. After that, I'll expplain what piece of data i'm wanting to extract.
var results = (from a in db.tblProducts
where (from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
}).Take(3)
.Any(
r =>
r.IdProductCode_Alpha== a.IdProductCode_Alpha&&
r.IdProductCode_Beta== a.IdProductCode_Beta&&
r.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName}).ToList();
Ok. I've changed some field and tables names to protect the innocent. :)
See this last line :-
select new {a.IdProduct, a.FullName}).ToList();
I wish to include in that the ReviewCount (from the subquery). I'm jus not sure how.
To help understand the problem, this is what the data looks like.
Sub Query
IdProductCode_Alpha = 1, IdProductCode_Beta = 2, IdProductCode_Gamma = 3, ReviewCount = 10
... row 2 ...
... row 3 ...
Parent Query
IdProduct = 69, FullName = 'Jon Skeet's Wonder Balm'
So the subquery grabs the actual data i need. The parent query determines the correct product, based on the subquery filters.
EDIT 1: Schema
tblProducts
IdProductCode
FullName
ProductFirstName
tblReviews (each product has zero to many reviews)
IdProduct
IdProductCode_Alpha (can be null)
IdProductCode_Beta (can be null)
IdProductCode_Gamma (can be null)
IdPerson
So i'm trying to find the top 3 products a person has done reviews on.
The linq works perfectly... except i just don't know how to include the COUNT in the parent query (ie. pull that result from the subquery).
Cheers :)
Got it myself. Take note of the double from at the start of the query, then the Any() being replaced by a Where() clause.
var results = (from a in db.tblProducts
from g in (
from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
})
.Take(3)
Where(g.IdProductCode_Alpha== a.IdProductCode_Alpha&&
g.IdProductCode_Beta== a.IdProductCode_Beta&&
g.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName, g.ReviewCount}).ToList();
While I don't understand LINQ completely, but wouldn't the JOIN work?
I know my answer doesn't help but it looks like you need a JOIN with the inner table(?).
I agree with shahkalpesh, both about the schema and the join.
You should be able to refactor...
r => r.IdProductCode_Alpha == a.IdProductCode_Alpha &&
r.IdProductCode_Beta == a.IdProductCode_Beta &&
r.IdProductCode_Gamma == a.IdProductCode_Gamma
into an inner join with tblProducts.

Resources