Linq outer join syntax - c#

I have the following query:
var query =
from modules in _Context.Modules
join moduleStrings in _Context.ModuleStrings on modules.MID equals moduleStrings.MID
join strings in _Context.Strings on moduleStrings.SID equals strings.SID
join stringTexts in _Context.StringTexts on strings.SID equals stringTexts.SID into stringsEmpty
from stringTexts in stringsEmpty.DefaultIfEmpty()
join languages in _Context.Languages on stringTexts.LID equals languages.LID
where modules.MID == MID && LID == languages.LID
select new GridData6S()
{
Name = strings.Name,
Text = stringTexts != null ? stringTexts.Text : ""
};
I want to join it so that I see the empty text if stringTexts is null.
It's probably some small thing, but I have been looking at this for an hour and can't figure it out. This is the closest I got.

You are filtering out any language that is not LID=languages.LID so when languages/stringTexts are null this condition will never be true.
Also as the only reason you seem to be joining to the languages table is to get the LID which is also the join condition, you could just skip joining to languages
The same is true for modules.....
This might help and is a little simpler
var query =
from moduleStrings in _Context.ModuleStrings
join strings in _Context.Strings on moduleStrings.SID equals strings.SID
join stringTexts1 in _Context.StringTexts.Where(x=>x.LID==LID) on strings.SID equals stringTexts.SID into stringsEmpty
from stringTexts in stringsEmpty.DefaultIfEmpty()
where moduleStrings.MID == MID
select new GridData6S()
{
Name = strings.Name,
Text = stringTexts != null ? stringTexts.Text : ""
};

Related

convert SQL to LINQ not working

I want to convert this SQL code to LINQ. Here is my SQL code:
SELECT Rooms.RoomName AS RoomNo, Beds.BedName AS Beds, Rooms.RoomType, ISNULL(CheckIn.CheckIntatus,'') AS Status
FROM CheckIn
INNER JOIN GuestBeds ON CheckIn.GuestBedId = GuestBeds.Id
AND (CheckIn.CheckInStatus = 1 OR CheckIn.CheckIntatus = 2 OR CheckIn.CheckSIntatus = 3)
RIGHT JOIN Beds ON GuestBeds.BedId = Beds.Id
INNER JOIN Rooms ON Beds.RoomId = Rooms.Id
LEFT JOIN Guests ON CheckIn.GuestId = Guests.Id
WHERE Beds.Active = 1 AND Rooms.Active = 1
ORDER BY RoomName, Beds
It works well which means it shows all the RoomName with CheckInStatus. If the Room is not presence in CheckIn table, ot will return the status as Null.
So I want to convert the code to LINQ. SO here is my LINQ code:
from b in Beds
join w in Rooms on b.RoomsId equals w.Id
where (a.CheckInStatus == 3 || a.CheckInStatus == 1 || a.CheckInStatus == 2)
join p in GuestBeds on b.Id equals p.BedId
join a in CheckIn on p.Id equals a.GuestBedId
join t in Guests on a.GuestId equals t.Id
where b.Active == true && w.Active == true
orderby w.RoomName
select new
{
RoomName = w.RoomName,
BedName = b.BedName,
Status = a.CheckInStatus
}
It didnt worked like the first code. It only show the data which contain CheckInStatus. I want it to show all the RoomName inside Room database
Normally I would post some rules for converting SQL to LINQ but this is complicated enough I think I'd need to make new rules. I commented out the references to Guests because as a LEFT JOIN it has no bearing on the answer.
Pull out the WHERE on individual tables and make them sub-queries:
var ActiveBeds = Beds.Where(b => b.Active == 1);
var ActiveRooms = Rooms.Where(r => r.Active == 1);
In LINQ, a RIGHT JOIN must be done by flipping the join to be a left join, so we will create the two sides as sub-queries.
Left side of RIGHT JOIN:
Translate the JOIN conditions that aren't part of an equi-join into a LINQ where clause on the appropriate tables (alternately this could be a subquery as above). The LEFT JOIN becomes a LINQ join/from ... DefaultIfEmpty() phrase, but as noted above isn't needed.
var CheckInsGuestBedsGuests = from c in CheckIn
where (c.CheckInStatus == 1 || c.CheckInStatus == 2 || c.CheckInStatus == 3)
join gb in GuestBeds on c.GuestBedId equals gb.Id
//join g in Guests on c.GuestId equals g.Id into gj
//from g in gj.DefaultIfEmpty()
select new { c, gb /*, g */ };
Right side of RIGHT JOIN:
The other side of the RIGHT JOIN includes an INNER JOIN so put them together in a sub-query:
var ActiveBedsRooms = from b in ActiveBeds
join r in ActiveRooms on b.RoomId equals r.Id
select new { b, r };
Finally, flip the sub-queries to create a left join using the same idiom as above:
var ans = from br in ActiveBedsRooms
join cgbg in CheckInsGuestBedsGuests on br.b.Id equals cgbg.gb.BedId into cgbgj
from cgbg in cgbgj.DefaultIfEmpty()
select new {
RoomNo = br.r.RoomName,
Beds = br.b.BedName,
br.r.RoomType,
Status = cgbg.c.CheckInStatus
};
NOTE: If you were not using LINQ to SQL, the Status expression would fail when cgbg is null and you would need
Status = cgbg?.c.CheckInStatus
but unfortunately LINQ to SQL/EF doesn't handle the null conditional operators yet.
BTW, nice query - brings back memories of when I used to write hotel front desk software :)

Adding second condition in LINQ JOIN,

I have looked around and found a few posts on adding a second condition to a JOIN clause but they are always instances of having one column link to another but in my instance I need to just have a column equal a certain value. The RAW SQL I am trying to imitate is:
LEFT OUTER JOIN dbo.TimeCardHeader AS tch2 on tch1.EmployeeID = tch2.EmployeeID && tch2.WeekEndingDate = #PayPeriod
As you can see my second join condition is to match a column value from the table to a variable. I have tried the following LINQ queires but they all fail.
join leftth2 in db.TimeCardHeaders on th1.EmployeeID equals leftth2.EmployeeID AND leftth2.WeekEndingDate == PayPeriod into leftjointh2
join leftth2 in db.TimeCardHeaders on th1.EmployeeID equals leftth2.EmployeeID && leftth2.WeekEndingDate == PayPeriod into leftjointh2
join leftth2 in db.TimeCardHeaders on new
{
employeeID = th1.EmployeeID,
weekEndingDate = leftth2.WeekEndingDate
} equals new
{
employeeID = leftth2.EmployeeID,
weekEndingDate = PayPeriod
}
The first two fail saying AND and && are not valid, the last fails saying leftth2 is not in the scope of the left side.
What is the proper way of doing this?
The condition
tch2.WeekEndingDate = #PayPeriod
doesn't feel like part of the join to me - it's not comparing data in two different rows. It feels like it should be part of what you're joining on, leading to:
join leftth2 in db.TimeCardHeaders.Where(p => p.WeekEndingDate == PayPeriod)
on th1.EmployeeID equals leftth2.EmployeeID into leftjointh2

linq to sql query with checkboxes where condition combination

if checkbox chkAus checked :
if (chkAus.Checked)
{
vAdvanceSearchResults = (from t in vAdvanceSearchResults
join imp in _bDataContext.Imprints on t.ImprintID equals imp.ID
join cc in _bDataContext.CountryCodes on imp.CountryID equals cc.ID
where cc.Code.Contains("AU")
select t).Distinct();**
}
if chkAus and chkNz are checked
if (chkNz.Checked && chkAus.Checked)
{
vAdvanceSearchResults = (from t in vAdvanceSearchResults
join imp in _bDataContext.Imprints on t.ImprintID equals imp.ID
join cc in _bDataContext.CountryCodes on imp.CountryID equals cc.ID
where cc.Code.Contains("AU") || cc.Code.Contains("NZ")
select t).Distinct();
}
The condition on linq query changes as the checkboxes are checked.
where cc.Code.Contains("AU") || cc.Code.Contains("NZ")
I have nearly 10 checkboxes, and got stuck on how to write that many conditions.
Any help please.
for example if there is chkUS :
then the combination with chkAus,chkNz,chkUS checkboxes the linq query would change.
where cc.Code.Contains("AU") || cc.Code.Contains("NZ") || cc.Code.Contains("US")
Put all of them in a list and then do a if list.contains(cc.Code)
var a = new List<string>(){"AU","NZ","US"};
var linq = (from t in vAdvanceSearchResults
join imp in _bDataContext.Imprints on t.ImprintID equals imp.ID
join cc in _bDataContext.CountryCodes on imp.CountryID equals cc.ID
where a.Contains(cc.Code)
select t).Distinct();
Create a list of selected checkboxes first. Like this.
var selectedCountries = new List<string>();
if (chkAus.Checked) selectedCountries.Add("AU");
if (chkNz.Checked) selectedCountries.Add("NZ");
if (chkUs.Checked) selectedCountries.Add("US");
//... And so on
And then modify your linq query to check whether this list contains the code or not, I mean reversing the comparison is an answer. Make sure you remove if condition for this linq query.
vAdvanceSearchResults = (from t in vAdvanceSearchResults
join imp in _bDataContext.Imprints on t.ImprintID equals imp.ID
join cc in _bDataContext.CountryCodes on imp.CountryID equals cc.ID
where selectedCountries.Contains(cc.Code)
select t).Distinct();
This will fix your problem.

Linq query join is not working

Hi i am trying to join two tables in c#. the join code is given below. The problem is that when there is null value for tourid in tb_abc then in will not include that row from tb_abc in the list.
return (from p in context.tb_abc
from o in context.tb_Second
where o.id==p.tourId
where p.driverId == driverId
select new abcBean
{
id=p.id,
name=o.name
}).ToList<abcBean>();
Can anyone tell me what i am doing wrong
You are not doing an inner join in that query. You are doing a cross join, its where you have two tables and join each record to every other record.
If you want to include rows that return null on one of the constraints you need a left outer join.
return (from p in tb_abc
join o in tb_Second on p.tourId equals o.id into po
where p.driverId == driverId
from subpo in po.DefaultIfEmpty()
select new abcBean
{
id=p.id,
name=(subpo == null ? String.Empty : subpo.Name)
}).ToList();
Consider these two sql statements:
The first a cross join:
select id, name
from tb_abc o,
tb_Second p
where
o.id = p.tourID
and p.driverID = #driverID
The second a left outer join:
select id, name
from tb_abc o
LEFT OUTER JOIN tb_Second p on o.id = p.tourID
where
p.driverId = #driverID
The second will give you one set of the records, that include the null value of o.id.
The first will give you something of a Cartesian product which you rarely want.
Linq's DefaultIfEmpty() puts the default value (null) into the record if it doesnt find a match for the one side, so it behaves like the left outer join.
you can use left outer join like
return (from p in context.tb_abc
join o in context.tb_Second on o.id==p.tourId into gt
where p.driverId == driverId
from subsecond in gt.DefaultIfEmpty()
select new abcBean
{
id=p.id,
name=(subsecond == null ? String.Empty : subsecond.Name)
}).ToList<abcBean>();

LINQ to Entities Join on Nullable Field where Null Implies "Match All"

I am attempting to run the following LINQ query using Entity Framework 5:
int taskId = 2;
query = from a in Table_A
where a.StatusCode != "DONE"
&& a.Inbound
join b in Table_B
on a.Id equals b.Id_Table_A
join c in Table_C
on a.State equals (c.State ?? a.State)
where 2 == c.Id_Task
&& b.DataType == c.DataType
select a.Id;
The line that is causing me problems is:
on a.State equals (c.State ?? a.State)
The "State" field in Table_C is nullable... and when it is null, it is used to imply "all states". As such, when "c.State" is null I want the record to be matched. If I were to write this in SQL, I would use the following:
JOIN Table_C ON Table_A.State = ISNULL(Table_C.State, Table_A.State)
Unfortunately, I am being given the following error:
The name 'a' is not in scope on the right side of 'equals'. Consider swapping the expressions on either side of 'equals'.
I will be grateful to anybody who can let me in on the secret to getting this working.
Thanks.
You can modify your code like:
int taskId = 2;
query = from a in Table_A
where a.StatusCode != "DONE"
&& a.Inbound
join b in Table_B
on a.Id equals b.Id_Table_A
from c in Table_C
where 2 == c.Id_Task
&& b.DataType == c.DataType
&& (c.State == null || a.State.Equals(c.State))
select a.Id;
A join is essentially a where clause, so here we can use the where clause due to the restrictions with join.
I managed to get this to work by moving the "DataType" check from the WHERE to the JOIN, and moving the "State" check from the JOIN to the WHERE. The resulting code that worked as I expected is as follows:
query = from a in Table_A
where a.StatusCode != "DONE"
&& a.Inbound
join b in Table_B
on a.Id equals b.Id_Table_A
join c in Table_C
on b.DataType equals c.DataType
where 2 == c.Id_Task
&& (c.State ?? a.State) == a.State
select a.Id;
Many thanks to everybody who has taken a look at this for me. :)
You can use "from" syntax instead of "join"
from a in TableA
from b in TableB
.Where(x => (x.Buy ?? a.Buy) == a.Buy
&& (x.Parity ?? a.Parity) == a.Parity)

Categories