Reputation: 507
I'm stuck converting below sql to LINQ query. Basically I just want to group my exam in my table grade then compute for the total number passed, failed, number of times taken and passing rate
SELECT testID,
(SELECT COUNT(testID) FROM tblGrade AS b
WHERE b.testID= a.testID AND b.Grade < 80) AS 'Failed',
(SELECT COUNT(testID) FROM tblGrade AS b
WHERE b.testID= a.testIDAND b.Grade >= 80) AS 'Passed',
--taken = failed + passed,
--passingrate = (passed / taken) * 100
FROM dbo.tblGrade AS a
GROUP BY testID
ORDER BY testID
EDIT: My solution below: It works but I think its not the best way, especially the failed and passed property.
var xx1 = _unitOfWork.tblGrade.GetAll().GroupBy(a => new { a.testID});
var xx2 = xx1.Select(b => new
{
testID= b.Key.testID,
failed = _unitOfWork.tblGrade.Query(filter: a => a.testID == b.Key.testID).Where(c => c.Grade < 80).Count(),
passed = _unitOfWork.tblGrade.Query(filter: a => a.testID == b.Key.testID).Where(c => c.Grade >= 80).Count(),
//taken = failed + passed,
//passingrate = (passed / taken) * 100
}).ToList();
Upvotes: 1
Views: 508
Reputation: 70538
This is how I would do it:
var h = list.GroupBy(a => a.testID)
.Select(a => {
int _failed = a.Count(g => g.Grade < 80);
int _passed = a.Count(g => g.Grade >= 80);
int _rate = (int)(_passed / (double)a.Count() * 100.0);
return new {
testID = a.Key,
failed = _failed,
passed = _passed,
taken = a.Count(),
rate = _rate,
};
});
Full test code:
void Main()
{
List<aGrade> list = new List<aGrade>() {
new aGrade() { Grade = 40, testID = 1 },
new aGrade() { Grade = 50, testID = 1 },
new aGrade() { Grade = 45, testID = 1 },
new aGrade() { Grade = 70, testID = 1 },
new aGrade() { Grade = 80, testID = 1 },
new aGrade() { Grade = 90, testID = 1 },
new aGrade() { Grade = 40, testID = 2 },
new aGrade() { Grade = 50, testID = 2 },
new aGrade() { Grade = 45, testID = 2 },
new aGrade() { Grade = 70, testID = 2 },
new aGrade() { Grade = 80, testID = 2 },
new aGrade() { Grade = 90, testID = 2 },
new aGrade() { Grade = 40, testID = 3 },
new aGrade() { Grade = 50, testID = 3 },
new aGrade() { Grade = 45, testID = 3 },
new aGrade() { Grade = 70, testID = 3 },
new aGrade() { Grade = 80, testID = 3 },
new aGrade() { Grade = 90, testID = 3 },
};
var h = list.GroupBy(a => a.testID)
.Select(a => {
int _failed = a.Count(g => g.Grade < 80);
int _passed = a.Count(g => g.Grade >= 80);
int _rate = (int)(_passed / (double)a.Count() * 100.0);
return new {
testID = a.Key,
failed = _failed,
passed = _passed,
taken = a.Count(),
rate = _rate,
};
});
h.Dump();
}
// Define other methods and classes here
public class aGrade
{
public int Grade { get; set; }
public int testID { get; set; }
}
NB - This code will work as is in LinqPad. (linqpad.com) I recommend linqpad for testing this type of code... makes your work, oh so easy. Try it.
Upvotes: 0
Reputation: 60503
Count()
can take a predicate (Expression<Func<T, bool>>
) as argument, so I think you may just do
var xx2 = xx1.Select(b => new
{
testID= b.Key.testID,
failed = b.Count(x => x.Grade < 80),
passed = b.Count(x => x.Grade >=80),
taken = b.Count()
})
.Select(b => new {
testID = b.TestID,
failed = b.failed,
passed = b.passed,
taken = b.taken,
passingrate = b.taken == 0 ? 0.0 : ((float)b.passed / b.taken) * 100
}).ToList();
The query syntax has the (usefull in this case) let
keyword, so it might be easier to read
var xx2 = from b in xx1
let failed = b.Count(x => x.Grade < 80)
let passed = b.Count(x => x.Grade >= 80)
let taken = failed + passed
select new {
testID = b.Key.TextID,
failed = failed,
passed = passed,
taken = taken,
passingrate = taken == 0 ? 0.0 : ((float)passed / taken) * 100
}
Upvotes: 1