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.
Related
I want to check if there is a person in the database who has exactly two specific addresses.
My proper SQL query:
SELECT name, id FROM person
WHERE person.name = 'Kxxx' AND person.firstname = 'Axxx'
AND EXISTS (
SELECT address.id FROM address INNER JOIN city
WHERE address.person_id = person.id AND city.name = 'Hxxx' AND address.h_number = '4')
AND EXISTS (
SELECT address.id FROM address INNER JOIN city
WHERE address.person_id = person.id AND city.name = 'Dxxx' AND address.h_number = '5')
;
I am trying to create (C# and QueryOver) but with no proper effects:
Person personAlias = null;
Address addressAlias = null;
City cityAlias = null;
var query = session.QueryOver(() => personAlias)
.Where(() => personAlias.Name == name)
.Where(() => personAlias.FirstName == firstName)
;
foreach (var addr in addresses)
{
var subQuery = QueryOver.Of(() => addressAlias)
.Where(() => addressAlias.HouseNumber == addr.HouseNumber)
.JoinAlias(() => addressAlias.CityRef, () => cityAlias)
.Where(() => cityAlias.Name == addr.CityName)
;
subQuery.Select(x => x.Id);
query.WithSubquery.WhereExists(subQuery);
}
This might be a silly question, but is there no reason you cannot do a COUNT()
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;
}
I am coding my way through the 101 linq examples, and I'm now at #106.
I am trying to rewrite query expressions in method/lambda syntax for my own learning.
Here is the example code:
List<Customer> customers = GetCustomerList();
List<Supplier> suppliers = GetSupplierList();
var custSuppliers =
from cust in customers
join sup in suppliers on cust.Country equals sup.Country into ss
from s in ss.DefaultIfEmpty()
orderby cust.CompanyName
select new
{
Country = cust.Country,
CompanyName = cust.CompanyName,
SupplierName = s == null ? "(No suppliers)" : s.SupplierName
};
Here is what I have so far:
var custSuppliers =
customers.GroupJoin(suppliers, c => c.Country, s => s.Country, (c, s) => new { Customers = customers, Suppliers = suppliers })
.OrderBy(i => i.Customers)
.SelectMany(x => x.Suppliers.DefaultIfEmpty(), (x, p) => // p is the many field (i.e. customers)
new
{
CompanyName = x.CompanyName, // no definition for CompanyName
Country = p.Country,
SupplierName = p.SupplierName == null ? "(No suppliers)" : p.SupplierName
});
My understanding is the SelectMany takes parameters X and P where X is the "left" table (i.e. there is at most 1 of them) and P is the "right" table where there might be N of them (or a null).
But instead of the X variable holding a single customer, it holds a collection of suppliers and customers.
Can anyone explain what is going on here?
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
};
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();