Null Values in Entity Framework - c#

var query = from section in load_sections.Sections
join course in load_sections.Courses
on section.Course_Id equals course.Course_Id
join faculty in load_sections.Faculties
on section.Faculty_Id equals faculty.Faculty_Id
select section;
I have some null values in my section.Faculty_Id which will not be equal to any row in faculty.Faculty_Id and it is just returning the records where section.Faculty_Id is not null...If section.Faculty_Id is not null, then it must return the other remaining fields of Table Courses

If you can't drop the join on faculty for whatever reason, you'll have to construct an outer join:
var query = from section in load_sections.Sections
join course in load_sections.Courses
on section.Course_Id equals course.Course_Id
join faculty in load_sections.Faculties
on section.Faculty_Id equals faculty.Faculty_Id into faculties
from f in faculties.DefaultIfEmpty()
select section;
This executes a GroupJoin with Faculties. The effect of the subsequent from f in faculties is that the grouping is flattened again by a SelectMany. .DefaultIfEmpty() creates the outer join.

Related

What's wrong with the joins in this LINQ query?

I'm trying to replicate the following SQL query in LINQ:
SELECT *
FROM Table1 AS D INNER JOIN Table2 AS DV ON D.Table1Id = DV.Table1Id
INNER JOIN Table3 AS VT ON DV.Table3Id = VT.Table3Id
INNER JOIN Table4 AS C ON DV.CurrencyId = C.CurrencyId
INNER JOIN Table5 AS FP ON DV.DVDate BETWEEN FP.StartDate AND FP.EndDate
INNER JOIN Table6 AS FX ON DV.CurrencyId = FX.FromCurrencyId AND FX.ToCurrencyId = 'USD' AND FX.FiscalPeriodId = FP.FiscalPeriodId
This is what I have in LINQ:
from d in db.Table1
join dv in db.Table2 on d.Table1Id equals dv.Table1Id
join vt in db.Table3 on dv.Table3Id equals vt.Table3Id
join c in db.Table4 on dv.CurrencyId equals c.CurrencyId
join fp in db.Table5 on dv.DVDate >= fp.StartDate && dv.DVDate <= fp.EndDate //error on this line
join fx in db.Table6 on dv.CurrencyId equals fx.FromCurrencyId && fx.ToCurrencyId equals "USD" && fx.FiscalPeriodId equals fp.FiscalPeriodId //error also on this line
The last two joins to fp and fx are the problem but it's not clear to me what's wrong, it doesn't seem to like && but there's no and keyword like there is an equals that replaces =.
I've removed the select portion from LINQ as it's not relevant to the problem and I'd like to avoid spending more time obfuscating table and field names.
"A join clause performs an equijoin. In other words, you can only base matches on the equality of two keys. Other types of comparisons such as "greater than" or "not equals" are not supported. To make clear that all joins are equijoins, the join clause uses the equals keyword instead of the == operator. "
reference: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/join-clause
you need to do this in the where clause. Like here:
https://stackoverflow.com/a/3547706/3058487
To do a join using composite keys, you need to do something like here:
new { dv.CurrencyId, fp.FiscalPeriodId } equals new { CurrencyId = fx.ToCurrencyId, fx.FiscalPeriodId }
Reference:
https://learn.microsoft.com/en-us/dotnet/csharp/linq/join-by-using-composite-keys

SQL to LINQ - Left Join Before Inner Join

So I have a SQL query that I would like to convert to LINQ.
Here is said query:
SELECT *
FROM DatabaseA.SchemaA.TableA ta
LEFT OUTER JOIN DatabaseA.SchemaA.TableB tb
ON tb.ShipId = ta.ShipId
INNER JOIN DatabaseA.SchemaA.TableC tc
ON tc.PostageId= tb.PostageId
WHERE tc.PostageCode = 'Package'
AND ta.MailId = 'Specification'
The problem I am struggling with is I cannot seem to figure out how to do a left join in LINQ before an inner join, since doing a left join in LINQ is not as clear to me at least.
I have found numerous examples of a LINQ inner join and then a left join, but not left join and then inner join.
If it helps, here is the LINQ query I have been playing around with:
var query = from m in tableA
join s in tableB on m.ShipId equals s.ShipId into queryDetails
from qd in queryDetails.DefaultIfEmpty()
join p in tableC on qd.PostageId equals p.PostageId
where m.MailId == "Specification" && p.PostageCode == "Package"
select m.MailId;
I have tried this a few different ways but I keep getting an "Object reference not set to an instance of an object" error on qd.PostageId.
LINQ is very new to me and I love learning it, so any help on this would be much appreciated. Thanks!
From my SQL conversion recipe:
JOIN conditions that aren't all equality tests with AND must be handled using where clauses outside the join, or with cross product (from ... from ...) and then where
JOIN conditions that are multiple ANDed equality tests between the two tables should be translated into anonymous objects
LEFT JOIN is simulated by using into joinvariable and doing another from from the joinvariable followed by .DefaultIfEmpty().
The order of JOIN clauses doesn't change how you translate them:
var ans = from ta in TableA
join tb in TableB on ta.ShipId equals tb.ShipId into tbj
from tb in tbj.DefaultIfEmpty()
join tc in TableC on tb.PostageId equals tc.PostageId
where tc.PostageCode == "Package" && ta.MailId == "Specification"
select new { ta, tb, tc };
However, because the LEFT JOIN is executed before the INNER JOIN and then the NULL PostageIds in TableB for unmatched rows will never match any row in TableC, it becomes equivalent to an INNER JOIN as well, which translates as:
var ans2 = from ta in tableA
join tb in tableB on ta.ShipId equals tb.ShipId
join tc in tableC on tb.PostageId equals tc.PostageId
where tc.PostageCode == "Package" && ta.MailId == "Specification"
select new { ta, tb, tc };
Use:
var query = from m in tableA
join s in tableB on m.ShipId equals s.ShipId
join p in tableC on s.PostageId equals p.PostageId
where m.MailId == "Specification" && p.PostageCode == "Package"
select m.MailId;
Your query uses a LEFT OUTER JOIN but it doesn't need it.
It will, in practice, function as an INNER JOIN due to your tc.PostageCode = 'Package' clause. If you compare to a column value in a table in a WHERE clause (and there are no OR clauses and you aren't comparing to NULL) then effectively all joins to get to that table will be treated as INNER).
That clause will never be true if TableB is null (which is why you use LEFT OUTER JOIN vs INNER JOIN) - so you should just use an INNER JOIN to make the problem simpler.

Entity Framework selecting distinct from an inner query based on Concat

The concat works, but the outer distinct query does not. The error is 'string does not contain a definition for 'role_name'... Any idea how to make this work?
(from results in ((from pmr in dbContext.project_member_role
join r in dbContext.role on pmr.project_member_role_id equals r.role_id
where pmr.member_id == memberId
select r.role_name)
.Concat(from m in dbContext.member
join r in dbContext.role on m.portal_role_id equals r.role_id
where m.member_id == memberId
select r.role_name))
select results.role_name).Distinct().ToList();

LINQ join queries on multiple table

I have struggling to run linq left on multiple tables.
tableA
Select all the (courseID, code, title) from courseInstances table
tableB
select (studyLevel_ID) from Courses table where courseID from tableA = CourseID from tableB. tableB has courseID
tableC
Select (StudyLevelDescription) from StudyLevel table where studyLevelID from tableB = studyLevel from tableC.
I believe I need left join on table A as I need all the records
I have done separate linq which are working fine but struggling to bring combine result
CourseInstances results
var processedCourseInstance =
(from _courseInstances in _uof.CourseInstances_Repository.GetAll()
join _courses in _uof.Courses_Repository.GetAll() on _courseInstances.CourseID equals _courses.CourseID
into a from b in a.DefaultIfEmpty()
orderby _courseInstances.CourseCode
select _courseInstances).ToList();
StudyLevel results for each course
var _CoursesStudyLevel_Lookup =
(from _course in _uof.Courses_Repository.GetAll()
join _studyLevel in _uof.StudyLevel_Repository.GetAll() on _course.StudyLevelId equals _studyLevel.StudyLevelID
select new {_course.CourseID, _course.StudyLevelId, _studyLevel.LevelDescription }).ToList();
I have managed to combine two results but NOT with LEFT join on CourseInstance table. This time I used LINQPad
from _courseInstances in CourseInstances
join _courses in Courses on _courseInstances.CourseID equals _courses.CourseID
join _studylevel in StudyLevels on _courses.StudyLevelId equals _studylevel.StudyLevelID
orderby _courseInstances.CourseCode
select new {_courseInstances.CourseID, _courseInstances.CourseCode, _courseInstances.CourseTitle, _courseInstances.UCASCode, _courses.StudyLevelId, _studylevel.LevelDescription, _studylevel.SLevelType }
for above SQL version as following;
SELECT [t0].[CourseID], [t0].[CourseCode], [t0].[CourseTitle],
[t0].[UCASCode], [t1].[StudyLevelId], [t2].[LevelDescription], [t2].[SLevelType]
FROM [CourseInstances] AS [t0]
INNER JOIN [Courses] AS [t1] ON [t0].[CourseID] = ([t1].[CourseID])
INNER JOIN [StudyLevel] AS [t2] ON [t1].[StudyLevelId] = ([t2].[StudyLevelID])
ORDER BY [t0].[CourseCode]
If i understand correctly, you want something like this?
from _courseInstances in CourseInstances
join c in Courses on _courseInstances.CourseID equals c.CourseID into courses
from _courses in courses.DefaultIfEmpty()
join sl in StudyLevels on _courses.StudyLevelId equals sl.StudyLevelID into studyLevels
from _studylevel in studyLevels.DefaultIfEmtpy()
orderby _courseInstances.CourseCode
select new {
_courseInstances.CourseID,
_courseInstances.CourseCode,
_courseInstances.CourseTitle,
_courseInstances.UCASCode,
_courses.StudyLevelId,
_studylevel.LevelDescription,
_studylevel.SLevelType
}
}
You can create a LINQ left join query with the into keyword and .DefaultIfEmpt().

LINQ and various joining sample

i just learning LINQ. so first of all i need to be familiar with join with linq. i search google for left outer and right outer join with linq and i got answer like
left outer join
var LeftJoin = from emp in ListOfEmployees
join dept in ListOfDepartment
on emp.DeptID equals dept.ID into JoinedEmpDept
from dept in JoinedEmpDept.DefaultIfEmpty()
select new
{
EmployeeName = emp.Name,
DepartmentName = dept != null ? dept.Name : null
};
right outer join
var RightJoin = from dept in ListOfDepartment
join employee in ListOfEmployees
on dept.ID equals employee.DeptID into joinDeptEmp
from employee in joinDeptEmp.DefaultIfEmpty()
select new
{
EmployeeName = employee != null ? employee.Name : null,
DepartmentName = dept.Name
};
from then code i just could not understand how it is left outer join because no left outer key word is use here. so please tell me how to understand that the join is left outer join or right outer.
when i will use linq then how like operator can be use. 'a%' or '%a' or '%a%'. i saw there is contain method which is bit different.
please discuss the two issue. thanks
The "join ... in ... on ... into" piece of LINQ query syntax, is translated into a GroupJoin().
GroupJoin() method, for each key in the outer list (or table), returns a list of elements in the inner list (or table) having the same key, or an empty list if such key doesn't exist.
Hence, the left outer join code of your question is clearer:
If JoinedEmpDept (i.e. the list of elements having the same key of the current examined outer list entry) is empty, dept is set to null (thanks to DefaultIfEmpty() method).
Translation in pseudo code:
for each employee in ListOfEmployees
get the list of dept having ID equal to empl.DeptID
and set them into JoinedEmpDept
then for each dept in JoinedEmpDept
(if empty iterates over a single null dept)
returns an new element containing:
employee.Name and dept.Name (or null if dept is null)
The right outer join instead, is basically a left outer join with outer and inner lists exchanged.
About the "like" question, you should use string.Contains("a") for '%a%', string.StartsWith("a") for 'a%', string.EndsWith("a") for '%a'
Example:
var query = from el in listOfStrings
where el.StartsWith("AB")
select el;
EDIT:
About the IN() operator question...
well, you can use Contains() also for that, or Any():
var inGroup = new []{ "Foo", "Bar" };
var query1 = from el in listOfStrings
where inGroup.Contains(el)
select el;
// or equally
var query2 = from el in listOfStrings
where inGroup.Any(x => el.Equals(x))
select el;
The left outer join is so because of this line:
from dept in JoinedEmpDept.DefaultIfEmpty()
which will get all of the employees, even if they are not in a department. The DefaultIfEmpty turns the join into an left outer join, when the SQL is generated.
See this blog post for more details: C#: Left outer joins with LINQ
Left join Tip,
Instead of:
from user in tblUsers
join compTmp1 in tblCompanies
on user.fkCompanyID equals compTmp1.pkCompanyID into compTmp2
from comp in compTmp2.DefaultIfEmpty()
You can write:
from user in tblUsers
from comp in tblCompanies.Where(c => c.pkCompanyID == user.fkCompanyID).DefaultIfEmpty()

Categories

Resources