Convert SQL Left Join to Linq Expression Left Join - c#

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

Related

Linq left join returns inner join

I am trying to perform an outer join in C# using Linq, the person mentoring me keeps saying I shouldn't try to do an outer join which isn't really an answer.
What I got from the other threads is that I need the .DefaultIfEmpty() where ever I may not have a record.
I tried it first on just the lines where there may be a missing information then added it to every line just to see if that was the problem.
Every time I run this I get only the inner join records. It works great other than it is not including the two records from my DB that only have information in the first two tables.
var sqlQuery =
from s in ctx.Suppliers
from sp in ctx.SupplierParts
.Where(sp => sp.SupplierID == s.SupplierID)
.DefaultIfEmpty()
from sm in ctx.SupplierManufacturerRelations
.Where(sm => sm.SupplierPNID == sp.SupplierPNID)
.DefaultIfEmpty()
from mp in ctx.ManufacturerParts
.Where(mp => mp.MfgPNID.Equals(sm.MfgPNID))
.DefaultIfEmpty()
from m in ctx.Manufacturers
.Where(m => m.ManufacturerID.Equals(mp.ManufacturerID))
.DefaultIfEmpty()
from im in ctx.ItemMasters
.Where(im => im.PreID == mp.PreID)
.Where(im => im.PartNumber == mp.PartNumber)
.DefaultIfEmpty()
from c in ctx.ComponentClasses
.Where(c => c.CCID == im.CCID)
.DefaultIfEmpty()
from um in ctx.UnitsOfMeasures
.Where(um => um.UOMID == sp.UOMID)
.DefaultIfEmpty()
select new
{ my variables}
var querylist = sqlQuery.Where(n => n.SupplierID == thisSupplier).ToList();
I also tried
from s in ctx.Suppliers
join sp in ctx.SupplierParts on s.SupplierID equals sp.SupplierID
join sm in ctx.SupplierManufacturerRelations on sp.SupplierPNID equals sm.SupplierPNID into spartgroup
from sm in spartgroup.DefaultIfEmpty()
join mp in ctx.ManufacturerParts on sm.MfgPNID equals mp.MfgPNID into mpartgroup
from mp in mpartgroup.DefaultIfEmpty()
join m in ctx.Manufacturers on mp.ManufacturerID equals m.ManufacturerID into mgroup
from m in mgroup.DefaultIfEmpty()
join im in ctx.ItemMasters
on new { key1 = (int)mp.PreID, key2 = (int)mp.PartNumber }
equals new { key1 = im.PreID, key2 = im.PartNumber }
into tpartgroup
from im in tpartgroup.DefaultIfEmpty()
join c in ctx.ComponentClasses on im.CCID equals c.CCID into fullgroup
from c in fullgroup.DefaultIfEmpty()
join um in ctx.UnitsOfMeasures on sp.UOMID equals um.UOMID
This SQL query works and doesn't omit the rows
SELECT Supplier.SupplierID
, SupplierPart.SupplierPNID
, SupplierPart.SupplierPN
, SupplierPart.Description
, SupplierManufacturerRelation.MfgPNID
, ManufacturerPart.PreID
, ManufacturerPart.PartNumber
, ItemMaster.CCID
, ItemMaster.Description AS Expr1
FROM Supplier
Inner JOIN SupplierPart
ON Supplier.SupplierID = SupplierPart.SupplierID
Left JOIN SupplierManufacturerRelation
ON SupplierPart.SupplierPNID = SupplierManufacturerRelation.SupplierPNID
Left JOIN ManufacturerPart
ON SupplierManufacturerRelation.MfgPNID = ManufacturerPart.MfgPNID
Left JOIN ItemMaster
ON ManufacturerPart.PreID = ItemMaster.PreID
AND ManufacturerPart.PartNumber = ItemMaster.PartNumber
WHERE Supplier.SupplierID = 9
For translating SQL to LINQ query comprehension:
Translate FROM subselects as separately declared variables.
Translate each clause in LINQ clause order, translating monadic operators (DISTINCT, TOP, etc) into functions applied to the whole LINQ query.
Use table aliases as range variables. Use column aliases as anonymous type field names.
Use anonymous types (new { ... }) for multiple columns.
Left Join is simulated by using a into join_variable and doing another from from the join variable followed by .DefaultIfEmpty().
Replace COALESCE with the conditional operator and a null test.
Translate IN to .Contains() and NOT IN to !...Contains()
SELECT * must be replaced with select range_variable or for joins, an anonymous object containing all the range variables.
SELECT fields must be replaced with select new { ... } creating an anonymous object with all the desired fields or expressions.
Proper FULL OUTER JOIN must be handled with an extension method.
So from your SQL, your query should look like:
var ans = from s in ctx.Suppliers
join sp in ctx.SupplierParts on s.SupplierID equals sp.SupplierID
join sm in ctx.SupplierManufacturerRelations on sp.SupplierPNID equals sm.SupplierPNID into smj
from sm in smj.DefaultIfEmpty()
join mp in ctx.ManufacturerParts on sm?.MfgPNID equals mp.MfgPNID into mpj
from mp in mpj.DefaultIfEmpty()
join im in ctx.ItemMasters on new { key1 = (int)mp.PreID, key2 = (int)mp.PartNumber } equals new { key1 = im.PreID, key2 = im.PartNumber } into imj
from im in imj.DefaultIfEmpty()
select new {
s.SupplierID, sp.SupplierPNID, sp.SupplierPN, sp.Description, sm.MfgPNID, mp.PreID, mp.PartNumber, im.CCID, Expr1 = im.Description
};

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

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

Left outer join using LINQ - yields different outputs

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.

How to use AND operator in LINQ Join

I have following SQL Query
SELECT * FROM KDMS_dynamic vd
INNER JOIN KDMS_definition tblKDMS ON tblKDMS.SystemID=vd.SystemID
LEFT OUTER JOIN KDMS_typeid tblKDMSType ON tblKDMS.TypeId=tblKDMSType.TypeId
INNER JOIN KDMS_configuration tblKDMSConfig ON tblKDMS.SystemID=tblKDMSConfig.SystemID
AND tblKDMSConfig.ConfigurationDate = (SELECT MAX(ConfigurationDate)
FROM KDMS_configuration vc
WHERE vc.SystemID=tblKDMSConfig.SystemID)
AND vd.LastUpdated=(SELECT MAX(LastUpdated) FROM KDMS_dynamic vd
WHERE vd.SystemID=tblKDMS.SystemID)
WHERE
DeletionDate IS NULL
AND LongDescription IS NOT NULL
AND tblKDMS.TypeId <> 1
As I have try convert the same in to LINQ but I can not due to AND OPERATOR use in Inner Join.
I am not aware how to use And Operator in LINQ , JOIN
As folloing the linq code which i try.
IQueryable<getKDMS> query = (from VD in this._db.GetTable<KDMS_dynamic>()
join TblKDMS in this._db.GetTable<KDMS_definition>() on VD.SystemID equals TblKDMS.SystemID
join TblKDMSType in this._db.GetTable<KDMS_typeid>().DefaultIfEmpty() on TblKDMS.TypeID equals TblKDMSType.TypeID
join TblKDMSConfig in this._db.GetTable<KDMS_configuration>() on TblKDMS.SystemID equals TblKDMSConfig.SystemID
&& TblKDMSConfig.ConfigurationDate == (from TblKDMS_conf in this._db.GetTable<KDMS_configuration>()
where TblKDMS_conf.SystemID == TblKDMSConfig.SystemID
select TblKDMS_conf.ConfigurationDate).Max())
As i have try with && but it did not work....
it is done as on new{x.field1,x.field2} equals new{y.field1,y.field2}
var somedata = (from TblKDMS_conf in this._db.GetTable<KDMS_configuration>()
where TblKDMS_conf.SystemID == TblKDMSConfig.SystemID select TblKDMS_conf.ConfigurationDate).Max();
Queryable<getKDMS> query = (from VD in this._db.GetTable<KDMS_dynamic>()
join TblKDMS in this._db.GetTable<KDMS_definition>() on VD.SystemID equals TblKDMS.SystemID
join TblKDMSType in this._db.GetTable<KDMS_typeid>().DefaultIfEmpty() on TblKDMS.TypeID equals TblKDMSType.TypeID
join TblKDMSConfig in this._db.GetTable<KDMS_configuration>() on new {TblKDMS.SystemID,TblKDMSConfig.ConfigurationDate} equals new{TblKDMSConfig.SystemID,somedata}
Move the AND condition to your WHERE clause. Writing
SELECT * FROM Table1
INNER JOIN Table2 ON *first condition* AND *second condition*
WHERE *third condition*
is exactly the same as writing
SELECT * FROM Table1
INNER JOIN Table2 ON *first condition*
WHERE *second condition* AND *third condition*
I think you need to use the where operator in place of the &&.

Categories