Left outer join using LINQ - yields different outputs - c#

I am trying to write left outer join using LINQ. The SQL looks like,
SELECT *
FROM Table1 td1
LEFT OUTER JOIN Table2
ON td1.ColumnName = td2.ColumnName
WHERE td2.ColumnName IS NULL
ORDER BY SomeColumns
If I run this query in SQL Query analyzer, it returns say 100 records. And my converted LINQ code returns 105 records.
I have written LINQ in 2 ways as,
Method 1:
var data= (from td1in Table1
join td2 in Table2.Where(a => a.ColumnName == (int?)null)
on td1.ColumnName equals td2.ColumnName into outer
from x in outer.DefaultIfEmpty()
orderby SomeColumns
select td1);
Method 2: This gives an exception as, failed to enumerate results
var data = from td1 in Table1
join td2 in Table2
on td1.ColumnName equals td2.ColumnName into outer
from item in outer.DefaultIfEmpty()
where item.ColumnName.Value == (int?)null
orderby somecolumns
select td1 ;
The column used in where clause is nullable int type.
The result returned in SQL analyzer seems to be correct one.
Please help me in getting the identical results.
Thanks

Try this query:
var data = from td1 in Table1
join td2 in Table2
on td1.ColumnName equals td2.ColumnName into outer
from item in outer.DefaultIfEmpty()
where item == null
orderby somecolumns
select td1 ;
In your original query that line item.ColumnName.Value == (int?)null was wrong, because you tried to retrieve value for all ColumnName even if item was null. I corrected it and now it should work fine.

Related

LINQ to Entiites, left outer join of a group by

I can build a SQL query easily that does the following.
For each row of 'Table1' I want a count of the number of related 'Table2' records that have a 'Status' not equal to 5. There might be no matches so I use a 'left outer join' and then within that use a 'group by' in order to find the total number of matches.
The following query works as SQL. It outputs either a null for the count because there are no matches at all or an actual integer count if there is at least one match.
select
Table1.Id,
Table2Outer.Count
from
Table1
left outer join
(
select
Table2.Id,
COUNT(*) as Count
from
Table2
where
Table2.Status != 5
group by
Table2.Id
) as Table2Outer on Table2Outer.Id = Table.Id
Unfortunately I cannot work out how to convert this to LINQ to Entities. The following does not even compile and I am stuck!
var x = (from t1 in ctx.Table1
join t2 in ctx.Table2 on { t1.Id, t2.Status } equals new { t2.Id, Status != 5 } into t2Outer
from t2OuterB in t2Outer.DefaultIfEmpty()
group t2Outer by ?);
Any ideas?
Use a subquery to count child records in the projection.
var x = from t1 in ctx.Table1
select new
{
t1.Id,
Count = (from t2 in ctx.Table2
where t2.Status != 5
where t2.Id == t1.Id
select t2).Count()
};

Linq join query error

I am trying to join multiple datatables to create a single datatable. Here is the query.
var row = from r0w1 in dt_vi.AsEnumerable()
join r0w2 in dt_workcenter.AsEnumerable()
on r0w1.Field<int>("wcID") equals r0w2.Field<int>("iD")
join r0w3 in dt_recipe.AsEnumerable()
on r0w1.Field<int?>("curingRecipeID") equals r0w3.Field<int?>("recipe_id") join r0w4 in dt_defect.AsEnumerable()
on r0w1.Field<int?>("defectID") equals r0w4.Field<int?>("defect_id") into ps
from r0w4 in ps.DefaultIfEmpty()
select r0w1.ItemArray.Concat(r0w2.ItemArray.Concat(r0w3.ItemArray.Concat(r0w4.ItemArray))).ToArray();
foreach (object[] values in row)
dt.Rows.Add(values);
I tried to join r0w1 & r0w4 as LEFT OUTER JOIN. But here I am getting the error
Object reference not set to an instance of an object
Error seems to be in
r0w4.ItemArray
May be r0w4 is not getting any value. What could be the possible reason ?
The problem is ps.DefaultIfEmpty() will return the default value (null in this case) when no row match and thus it is throwing that error.
You can change it like this:-
r0w3.ItemArray.Concat(r0w4 != null ? r0w4 .ItemArray : new object[] {}))

Need some help in lambda expression from SQL query

I have this SQL query:
select
SubCaseNumber, MySaleries.WorkDate, stscreator.name, Status, SheetId
from
(select *
from
(select distinct
Sheets.SheetID SheetID, ShtInfos.SheetInfoID SheetInfoID,
ShtInfos.Creator_Id STSCreatorID, ShtUsers.User_ID STSFitterID,
Sheets.Status, ShtInfos.workdate, ShtInfos.SubCase_SubCaseId
from [Sheets]
left join [SheetInfoes] ShtInfos on sheets.SheetInfo_SheetInfoId = ShtInfos.SheetInfoId
left join [SheetUsers] ShtUsers on Sheets.SheetID = ShtUsers.Sheet_SheetID) AllSheets
where
(stsfitterID = '08153661-6520-4435-81e6-6064084db74d'
or stscreatorid = '08153661-6520-4435-81e6-6064084db74d')
and Status = 1) MySaleries
join
[SubCases] SubCases on SubCase_SubCaseId = SubCases.SubCaseId
join
[AspNetUsers] STSCreator on STSCreator.Id = MySaleries.STSCreatorID;
(returning 8 rows - correct)
And I have written the following Linq query to implement the SQL in Linq:
from Sht in Sheets
join SI in SheetInfoes on Sht.SheetInfo_SheetInfoId equals SI.SheetInfoId
join SC in SubCases on SI.SubCase_SubCaseId equals SC.SubCaseId
join ShtUsr in SheetUsers on Sht.SheetId equals ShtUsr.Sheet_SheetId
join STSUsr in AspNetUsers on SI.Creator_Id equals STSUsr.Id
where (ShtUsr.User_Id == "08153661-6520-4435-81e6-6064084db74d" || SI.Creator_Id == "08153661-6520-4435-81e6-6064084db74d") && SI.Status == 1
select new {SC.SubCaseNumber, SI.WorkDate, STSUsr.Name, Sht.Status, Sht.SheetId}
Returning 50 rows - should bee 8 rows too.
I have following tables:
[SheetInfoes], [Sheets], [SubCases], [AspNetUsers], [SheetUsers]
What am I doing wrong?
Your join conditions in the SQL you posted are LEFT joins. Your joins in the code are just joins without any filtering.
Example:
from maintable in Repo.T_Whatever
from xxx in Repo.T_ANY_TABLE.Where(join condition).DefaultIfEmpty()
I'd set it up something like this:
var query = (
from Sht in Sheets
from SheetInfoes
.where(x => x.SheetInfoId == Sht.SheetInfo_SheetInfoId)
.DefaultIfEmpty() // <== left join
from ShtUsr in SheetUsers
.where(x => x.SheetId == ShtUsr.Sheet_SheetId)
.DefaultIfEmpty() // <== left join
//You'll need to finish it
Take a look at this for a more info: Left Outer Joins

Convert SQL Left Join to Linq Expression Left Join

I have a query from SQL and I'm doing a left join. It's working ok.
SELECT Table1.Id, Table1.Comments, Table1.IdListDef
FROM Table2 INNER JOIN Table1 ON Table2.Id = Table1.IdListDef
LEFT JOIN Table3
ON Table1.Id = Table3.IdComments
WHERE Table1.IdListDef = 36 and Table2.IdRev = 1075 and Table3.IdAutor IS NULL
I need to transfrom this query to Linq Expression from C#. How can I do it? I don't know how to transform this query that contains left join.
It should look something like this:
var result = (
from item1 in table1
join item2 in table2 on item1.IdListDef equals item2.Id
join item3 in table3 on item1.Id equals item3.IdComments into finalGroup
from finalItem in finalGroup.DefaultIfEmpty()
where item1.IdListDef == 36 && item2.IdRev == 1075 && finalItem.IdAutor == null
select new
{
item1.Id, item1.Comments, item1.IdListDef
}).ToList();
Addition to your comment, if you're willing to see if any item has id of your outer parameter you could use linq Any extension method:
bool idExists = result.Any(item => item.id == idAutor);
TRY THIS QUERY
VAR OBJLIST=(FROM A IN CONTEX.TABLE2
FROM B IN CONTEX.TABLE1.WHERE(X=>X.IdListDef==a.Id && B.IdListDef==36 && B.IdRev==1075 )
FROM C IN CONTEX.TABLE3.WHRE(X=>X.IdComments==a.Id).DefaultEmpty()
where C.IdAutor==NULL
select new{a.Id, a.Comments, a.IdListDef }).ToList()

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

Categories