MVC 5 Linq-SQL Performing search from 3 joined Tables - c#

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

Related

EF Core 2.1 group by with skip and take

I a currently "paging" through an IQueryable that has many fields { Table1Id, Table1Label, IsActive, ...} and there can be mulitple records in IQueryable result for a PdcId, like the following:
var result = from a in _entities.table1
join b in _entities.table2 on new { a.Table1Id, a.Table1LevelId } equals new { Table1Id = b.Table2Id, Table1LevelId = b.Table2LevelId }
join c in _entities.Table3 on a.Table1Id equals c.Table1Id into cc from ccc in cc.DefaultIfEmpty()
where a.Valide == true
select new MeteringPointDetailModel
{
Table1Id = a.Table1Id,
Table1Label = a.Label,
IsActive = a.IsActive,
Table3Label = ccc.Label,
};
I tried this code but when i see the result generating in sql using sql profiler, the query is running without stop !! (generate multiple sql query ).
var data = await result.Where(i => result.GroupBy(p => p.Table1Id)
.Select(t => t.Key)
.Skip(query.Page).Take(query.PageSize)
.Contains(i.Table1Id)).ToListAsync();
How would I do this if I wanted to first group by Table1Id and then skip and take on the distinct Table1Id.
for example: if I have a result that has two records, one ends up being # 50 and the other 51, if I page by 50, I won't get record 51, and I want it.
That's what i did and worked for me :
Solution 1
var dataTable1 = (from a in _entities.table1
where a.Valide == true
select new {...}).Skip(query.Page).Take(query.PageSize);
var result = from a in dataTable1
join b in _entities.table2 on new { a.Table1Id, a.Table1LevelId } equals new { Table1Id = b.Table2Id, Table1LevelId = b.Table2LevelId }
join c in _entities.Table3 on a.Table1Id equals c.Table1Id into cc from ccc in cc.DefaultIfEmpty()
select new MeteringPointDetailModel
{
Table1Id = a.Table1Id,
Table1Label = a.Label,
IsActive = a.IsActive,
Table3Label = ccc.Label,
};
var data = await result.ToListAsync();
Solution 2
var result = from a in _entities.table1
join b in _entities.table2 on new { a.Table1Id, a.Table1LevelId } equals new { Table1Id = b.Table2Id, Table1LevelId = b.Table2LevelId }
join c in _entities.Table3 on a.Table1Id equals c.Table1Id into cc from ccc in cc.DefaultIfEmpty()
where a.Valide == true
select new MeteringPointDetailModel
{
Table1Id = a.Table1Id,
Table1Label = a.Label,
IsActive = a.IsActive,
Table3Label = ccc.Label,
};
result = !string.IsNullOrWhiteSpace(query.Table3Label) ? result.Where(c => c.Table3Label.ToLower().Contains(query.Table3Label.ToLower())) : result;
var table1Ids = await result.OrderBy(p => p.Table1Id)
.Select(p => p.Table1Id).Distinct()
.Skip(query.Page).Take(query.PageSize)
.ToListAsync();
var data = await result.Where(p => table1Ids.Contains(p.Table1Id)).ToListAsync();
Solution 2 is more useful if there are clause condition (search criteria) in join tables as specified in the example.
Hope it will help someone.

linq to object query to exclude 0

I have a Linq query as below.
var DataSource = from m in product
select new { Class = m.Class, Id = (new Make(m.Id)).ProductName};
I instantiate a class called Make and fetch the ProductName based on the Id.
Some of the Id's are 0.
Is there a way I can exclude all the Id's that are 0?
Sure, just do this:
var DataSource = from m in product
where m.Id != 0
select new
{
Class = m.Class,
Id = (new Make(m.Id)).ProductName
};
You're looking for the where clause:
where m.Id != 0
var DataSource = from m in product
where m.Id != 0
select new
{
Class = m.Class,
Id = (new Make(m.Id)).ProductName
};
Try this:
var DataSource = from m in product
where m.Id != 0
select new { Class = m.Class, Id = (new Make(m.Id)).ProductName};

self referential join using linq

My database has a students table:
StudentID int PK
StudentName varchar
FamilyID int (Nullable)
If a student has siblings in the database, they will share a familyID. If a student has no siblings, familyID should be null.
Using Linq, given a StudentID, how do a return a list containing a student and all his siblings (if any)?
A join with an into should do the trick.
var query = from s in students
join s2 in students.Where(x => x.StudentId != s.StudentId) on s.FamilyId equals s2.FamilyId into siblings
select new
{
Student = s,
Siblings = siblings,
};
You can add a query.FirstOrDefault(x => s.StudentId == yourStudentId) in order to get a specific StudentId
Using a LinQ method chain, this will return a list of only the siblings:
var siblings = students.Where(s => s.FamilyId == students.Single(st => st.StudentId == id).FamilyId).ToList();
or in 2 steps so you could provide checks on the student-instance:
var student = students.Single(st => st.Id == id);
var siblings = students.Where(s => s.FamilyId == student.FamilyId).ToList();
You can do something like this
List<Student> lstStd = new List<Student>();
var student = (from s in students
where s.studentid = studentid
select s).FirstOrDefault();
lstStd.Add(student);
if(student!=null)
{
if( student.FamilyId !=null)
{
lstStd.AddRange( (from s in students
where s.FamilyId == student.Familyid
&& s.studentid != student.studentid
select s).ToList<Student>());
}
}
var sid = 123;
var query = from s in Students
where (from s2 in Students where s2.Id == sid select s2.FamilyId).FirstOrDefault() == s.FamilyId
&& s.FamilyId != null
select s;
if i understand your question correctly. you are looking for the family members of a specified student id. this answer is based on the assumption that you are only looking for one family at a time, and not a list of all families.

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

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

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

Categories