Question

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();
Était-ce utile?

La solution

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
          }

Autres conseils

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top