Need help with converting SQL to LINQ - LEFT JOIN with Count - c#

I need help converting the following SQL query into LINQ:
select s.teacherid,t.lastname,t.firstname,t.title,t.grade, count(s.TeacherID)
from Teacher t
left join Student s on t.teacherid = s.teacherid
and t.isactive = 1
and s.isactive = 1
group by s.TeacherID,t.lastname,t.firstname,t.title,t.grade
I tried the following but it is not returning teacher records who have no students:
var teachers =
(from t in Teachers
join s in Students on t.TeacherID equals s.TeacherID
into results
where t.IsActive == true
from r in results
group r by new { r.TeacherID, r.Teacher.FirstName, r.Teacher.LastName, r.Teacher.Title, r.Teacher.Grade} into g
select new { TeacherID = g.Key.TeacherID,FirstName = g.Key.FirstName, LastName = g.Key.LastName, Title=g.Key.Title, Grade = g.Key.Grade}
);
Thank you in advance!

In order to do a left join you will need to use DefaultIfEmpty() method like so:
from r in results.DefaultIfEmpty()

var teachers =
(from t in Teachers
join s in Students on t.TeacherID equals s.TeacherID
into results
where t.IsActive == true
from r in results.DefaultIfEmpty()
group r by new { r.TeacherID, r.Teacher.FirstName, r.Teacher.LastName, r.Teacher.Title, r.Teacher.Grade} into g
select new { TeacherID = g.Key.TeacherID,FirstName = g.Key.FirstName, LastName = g.Key.LastName, Title=g.Key.Title, Grade = g.Key.Grade}
);

I did some research and found a solution. The following expression fixed it:
var results = Teachers
.Where(t => t.IsActive == true)
.Select(t =>
{
TeacherID = t.TeacherID,
FirstName = t.FirstName,
LastName = t.LastName,
Title = t.Title,
Grade = t.Grade,
Count = t.Students.Where(s => s.IsActive == true).Count()
});
results.ToList().Dump();

Related

Join two linq queries on one key column to get one result set

Here I want to join the out put of the first query(one column) to the result of the 2nd query to get a one result set. How can I merge them.(CONCAT doesn't work as required. eg: var query2 = query.concat(query1);)
var query = (from PP in _db.paymentPlans
join APP in _db.Applications on PP.applicationID equals APP.ApplicationId
join C in _db.Courses on APP.courseID equals C.courseID
where PP.active == true && APP.agentID == agentID
orderby C.courseID ascending
group new {C,PP} by new {C.courseID} into totalRecievable
select new PdPpAppCourseModel
{
courseID = totalRecievable.Key.courseID,
totalAmount = totalRecievable.Sum(x => x.PP.totalAmount)
}).ToList();
var query1=(from PD in _db.paymentDetails
join PP in _db.paymentPlans on PD.paymentPlanID equals PP.paymentPlanID
join APP in _db.Applications on PP.applicationID equals APP.ApplicationId
join C in _db.Courses on APP.courseID equals C.courseID
where PP.active == true && APP.agentID == agentID
orderby C.courseID ascending
group new { C,PD } by new { C.courseID, C.cricosCode, C.courseName } into paymentsCourseWise
select new PdPpAppCourseModel
{
courseID = paymentsCourseWise.Key.courseID,
cricosCode = paymentsCourseWise.Key.cricosCode,
courseName = paymentsCourseWise.Key.courseName,
paidAmount = paymentsCourseWise.Sum(x => x.PD.paidAmount)
}).ToList();
You could join query1 and query like this
var result = (from q1 in query1
join q in query on q1.courseID = q.courseID
select new PdPpAppCourseModel
{
courseID = q1.Key.courseID,
cricosCode = q1.Key.cricosCode,
courseName = q1.Key.courseName,
paidAmount = q1.Sum(x => x.PD.paidAmount),
totalAmount = q.totalAmount
}).ToList();

Linq To Sql Skip Take

I want to save each icon path into a variable, from the query bellow , only PathIcon1 has value . The remain path icon are empty
Query
using (CarteringServiceClientDataContext dc = new CarteringServiceClientDataContext())
{
result = (from a in dc.GetTable<tblSupplier>()
join b in dc.GetTable<tblCity>()
on a.CityId equals b.Id
join c in dc.GetTable<tblZone>()
on b.ZoneId equals c.Id
let r = (from re in dc.GetTable<tblClientReview>()
where re.SupplierId == a.Id
select re.note).Average()
let i = (from im in dc.GetTable<tblSupplierItem>()
where im.SupplierId == a.Id
select im.tblItem.IconPath).ToArray()
select new SearchResult
{
CompanyId = a.Id,
CompanyName = a.Company,
Localisation = a.Locality,
City = b.Name,
Zone = c.Name,
Rating = r.ToString(),
PathIcon1 = i.Take(1).SingleOrDefault(),
PathIcon2 = i.Skip(1).Take(1).SingleOrDefault(),
PathIcon3 = i.Skip(2).Take(1).SingleOrDefault(),
PathIcon4 = i.Skip(3).Take(1).SingleOrDefault(),
PathIcon5 = i.Skip(4).Take(1).SingleOrDefault()
}).ToList<SearchResult>();
}
A part from PathIcon1, the remaing PathIcon are null
using (CarteringServiceClientDataContext dc = new CarteringServiceClientDataContext())
{
result = (from a in dc.GetTable<tblSupplier>()
join b in dc.GetTable<tblCity>()
on a.CityId equals b.Id
join c in dc.GetTable<tblZone>()
on b.ZoneId equals c.Id
let r = (from re in dc.GetTable<tblClientReview>()
where re.SupplierId == a.Id
select re.note).Average()
let i = (from im in dc.GetTable<tblSupplierItem>()
where im.SupplierId == a.Id
select im.tblItem.IconPath).ToArray().Add("test")
select new SearchResult
{
CompanyId = a.Id,
CompanyName = a.Company,
Localisation = a.Locality,
City = b.Name,
Zone = c.Name,
Rating = r.ToString(),
PathIcon1 = i.Take(1).SingleOrDefault(),
PathIcon2 = i.Skip(1).Take(1).SingleOrDefault(),
PathIcon3 = i.Skip(2).Take(1).SingleOrDefault(),
PathIcon4 = i.Skip(3).Take(1).SingleOrDefault(),
PathIcon5 = i.Skip(4).Take(1).SingleOrDefault()
}).ToList<SearchResult>();
}
Try this if you are get PathIcon2 value as "test" your problem isn't skip or take. Just i list includes one item. Adn I think so.

Translate SQL statement with SUM() in Entity

I try to translate this SQL code :
SELECT w.Id, w.LastName, w.FirstName, SUM(d.Price*dt.Number) AS somme
FROM Waiter w
INNER JOIN Client c on w.Id = c.WaiterId
INNER JOIN DisheOnTable dt on c.Id = dt.ClientId
INNER JOIN Dishe d on dt.DisheId = d.Id
GROUP BY w.Id, w.LastName, w.FirstName
ORDER BY somme DESC;
in entity framework.
I tried something like this
var query2 = (from w in db.Waiter
join c in db.Client on w.Id equals c.WaiterId
join dt in db.DisheOnTable on c.Id equals dt.ClientId
join d in db.Dishe on dt.DisheId equals d.Id
group w by new { w.Id, w.LastName, w.FirstName } into g
//orderby g.Select() descending
select new
{
id = g.Key.Id,
lastname = g.Key.LastName,
firstname = g.Key.FirstName,
total = g.Sum(q => q.)
});
but my sum doesn't work (after multiple research and try) and i don't know how to multiply my variables.
PS : The SQL statement works well, i tried it.
Thank you for helping guys ! :)
You need to group on both dish and DishOnTable alias as Price is in Dish and Number is in DishOnTable:
group new{ d,dt} by new {w.Id, w.LastName, w.FirstName} into g
and now sum the columns which you want from it
select new {
id = g.Key.Id,
lastname = g.Key.LastName,
firstname = g.Key.FirstName,
total = g.Sum(q => q.d.Price * q.dt.Number)
}).OrderBy(x=>x.total)

MVC 5 Linq-SQL Performing search from 3 joined Tables

Using this model, I would like to perform a left outer join of the course table to the student table and display them with a search dropdown menu on the courses.
My MVC code is :
var query = from c in db.Students
join o in db.Enrollments on c.StudentID equals o.StudentID
join co in db.Courses on o.CourseID equals co.CourseID into sr
from x in sr.DefaultIfEmpty()
select new Student
{
FirstName=c.FirstName,
LastName=c.LastName,
EnrollmentDate=c.EnrollmentDate,
MiddleName=c.MiddleName,
StudentID=c.StudentID
//StudentName = c.FirstName.ToString(),
//CourseID = x.CourseID.ToString(),
//CourseName = x.Title.ToString()
//== null ? -1 : x.Title
};
if (!string.IsNullOrEmpty(course))
{
students = query.Where(x => x.CourseName == course).Select(item=>new Student(){FirstName = c.FirstName.ToString()}).ToList();
}
return View(students);
But I can't get it to work. Can someone please enlighten me on how to correctly do this.
This is the sample screen :
public List<Student> GetStudentsByCourseName(string courseName)
{
var list = new List<Student>();
var course = db.Courses.SingleOrDefault(o => o.Title == courseName);
if (course != null)
{
list = course.Enrollments.Select(o => new Student {
FirstName = o.Student.FirstName,
LastName = o.Student.LastName
}).ToList();
}
return list;
}

Linq with conditional joins

I couldn't convert the following left join SQL to linq:
select Students.StudentID, StudentAddresses.state
from Students left join Studentaddresses on (Students.StudentID = Studentaddresses.StudentID and StudentAddresses.Active=1)
where (StudentAddresses.Rank =1 or StudentAddresses.StudentID is null)
and Students.StudentID =3
A student can have zero record or multiple records in the Student Address table, but only one of the records can be active and rank=1.
I was able to do a left join in linq and make it work for normal situation. But if a student has two inactive records in the Student table, I don't know how to make the student record appear only once in the final result. Can anyone please help?
Use Distinct() to collapse duplicates.
var LeftJoin = (from student in Students
join address in (from address1 in StudentAddresses where address.Active select address1)
on student.StudentID equals address.StudentId
into JoinedStudentAddress
from joined in JoinedStudentAddress.DefaultIfEmpty()
select new
{
StudentID = student.StudentID,
State = joined != null ? joined.State : null
}).Distinct();
Alternate syntax
var LeftJoin = Students.GroupJoin( StudentAddress.Where( a => a.Active ),
s => s.StudentID,
a => a.StudentID,
(s,a) => new { Student = s, Addresses = a } )
.SelectMany( j = > j.Addresses.DefaultIfEmpty()
(s,a) => new {
StudentID = s.Student.StudentID,
State = a != null ? a.State : null
})
.Distinct();
This would be the SQL statement converted to linq:
var q = from student in Students
from adress in Studentaddresses.Where(x => student.StudentID == x.StudentID && x.Active).DefaultIfEmpty()
where (adress.Rank == 1 || adress.StudentID == null) && student.StudentID == 3
select new
{
StudentID = student.StudentID,
State = adress.state
};

Categories