SQL to LINQ with outer apply - c#

I am not able convert sql to linq because of outer apply
select * from dbo.Table1 l
inner join dbo.Table2 d on d.LoanId = l.Id
inner join dbo.Cash cOriginal on cOriginal.DealId = d.Id and cOriginal.IsOriginal = 1
outer apply (select top 1 * from dbo.Cash cActive
where cActive.DealId = d.ID and cActive.IsOriginal = 0
order by cActive.CreatedOn desc) cActiveRes
I am started something like this:
var q = from x in _repo.Queryable<Table1>()
join Table2 in _repo.Queryable<Table2>() on x.Id equals Table2.LoanId
join cOriginal in _repo.Queryable<Cash>() on Table2.Id equals
cOriginal.DealId
// now Outer Apply should come?
// fActive in _repo.Queryable<Cash>()

The easiest way it to run your SQL query directly letting EF to materialize the result. It might look like this (depending on version of EF you use):
var result = ((IObjectContextAdapter)_repo).ObjectContext.ExecuteStoreQuery<Table1>(
#"SELECT your query here");

Related

How to handle linq join query when join on id is not available in the table c#

I am not trying to join my table using left outer join in LINQ where one of my join conditions does not satisfy. How can I still get the default record in my dataset? My SQL query runs perfectly fine but my join query is not returning the data.
Below is my SQL query where my left outer join works fine:
select
w.issueid as Issue
from worklog w
join jiraissue as j on w.issueid=j.ID
join issuetype AS ty ON ty.ID = j.issuetype
join project AS p on p.ID=j.PROJECT
left outer join customfieldvalue cfv on cfv.ISSUE = w.issueid
Below is my LINQ query in C# where if cfv.issue in the last join is not available in the table, I want to still return the default column.
var data = (from w in worklogs
join i in issuetypes on j.issuetype equals i.ID
join p in projects on j.PROJECT equals p.ID into table0
from c in table0.DefaultIfEmpty()
join cfv in customfieldvalues on w.issueid equals cfv.ISSUE into table1
from d in table1.DefaultIfEmpty()
{
IssueKey = l.Key.pkey + '-' + l.Key.issuenum,
Hours = l.Sum(w => w.timeworked)
}).ToList();
Any help is appreciated.
Thank you.

Linq to sql join with multiple "OR" filters

I need to implement this in Linq-to-sql
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s ON c.Room = s.Entry_Bar_Code
OR c.HomeRoom = s.Entry_Bar_Code
WHERE s.id = 1021645
All the research I've done on this says that linq-to-sql can't support an "OR" multiple join, and the suggestions are to instead do two joins like this:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s ON c.Room = s.Entry_Bar_Code
LEFT OUTER JOIN dbo.Lab_Space s2 ON c.HomeRoom = s2.Entry_Bar_Code
WHERE s.id = 1021645
Those aren't actually the same query though as they'll return different results. Short of just putting the raw SQL into my C# program at this point, is there any way to accomplish the above?
Let's start from beginning. If you use WHERE with column from OUTER JOIN table it means that your query:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s ON c.Room = s.Entry_Bar_Code
OR c.HomeRoom = s.Entry_Bar_Code
WHERE s.id = 1021645
is logically equivalent to:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
JOIN dbo.Lab_Space s
ON c.Room = s.Entry_Bar_Code
OR c.HomeRoom = s.Entry_Bar_Code
WHERE s.id = 1021645;
And this could be achieved with CROSS JOIN(pseudocode):
var q = from c in Collector_Capital_Equipment
from s in Lab_Space
where s.id == 1021645
&& (s.Entry_Bar_Code == c.Room || c.HomeRoom == s.Entry_Bar_Code)
select ...
I assume that you really want to generate query:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s
ON (c.Room = s.Entry_Bar_Code OR c.HomeRoom = s.Entry_Bar_Code)
AND s.id = 1021645
which could be represented as:
SELECT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s
ON c.Room = s.Entry_Bar_Code AND s.id = 1021645
INTERSECT
SELECT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s
ON c.HomeRoom = s.Entry_Bar_Code AND s.id = 1021645
And above query could be achieved with LINQ using set operators.
db<>fiddle demo
I don't think I've ever seen someone use an OR clause on a join before. Does MS SQL Server even support that in SQL?
I'd probably just split this off into two queries, to be honest.
SELECT entry_bar_code
FROM dbo.Lab_Space WHERE id = 1021645;
With the result from that being fed into
SELECT DISTINCT *
FROM dbo.Collector_Capital_Equipment
WHERE c.room == <barcode> OR c.homeRoom == <barcode>

LINQ Left Join with multiple ON OR conditions

I'm sorry for telling that I've a little bit weak on LINQ, I always do write SQL query before I start working on the complicated LINQ.
I want to ask that how to convert this SQL Query into LINQ with LEFT JOIN with multiple ON conditons with the OR operator.,
m.MerchandiseId will be use for twice in ON condition
SELECT
*
FROM
Inbox AS i
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS m ON
u.MerchandiseId = m.MerchandiseId
OR
i.ToMerchantId = m.MerchandiseId
WHERE
i.ToCompanyId = 10
OR
i.FromCompanyId = 10
var message = (from i in db.Inbox
join u in db.User on i.FromUserId equals u.UserId
join m in db.Merchandise on u.MerchandiseId equals m.MerchandiseId //here I want to ON i.MerchantId = m.MerchandiseId, but it doesn't allow
where i.ToCompanyId == user.CompanyId || i.FromCompanyId == user.CompanyId
orderby i.CreatedAt descending
group m.MerchandiseId by new { m.MerchandiseId, m.MerchandiseName } into grp
select new
{
MerchandiseId = grp.Key.MerchandiseId,
MerchandiseName = grp.Key.MerchandiseName,
InboxMessage = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.InboxMessage).FirstOrDefault(),
CreatedAt = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.CreatedAt).FirstOrDefault(),
}).ToList();
The bottom LINQ Query I've write for it. However, I just can work on the left join with multiple ON clause in LINQ. Appreciate if someone would help me on this. Thanks!
I don't believe Linq supports the use of the OR operator with multiple columns, but that said, I wouldn't use OR even in SQL as it makes the join's intention unclear and it also obscures where the data originated from - it also isn't immediately clear what happens if there are multiple matches for each column. Instead I would JOIN twice on the different columns and let the projection-clause handle it:
SELECT
*
FROM
Inbox
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS userMerchant ON u.MerchandiseId = userMerchant.MerchandiseId
LEFT OUTER JOIN Merchandise AS inboxMerchant ON Inbox.ToMerchantId = inboxMerchant .MerchandizeId
WHERE
Inbox.ToCompanyId = 10
OR
Inbox.FromCompanyId = 10
This can then be translated into Linq using the LEFT OUTER JOIN approach ( How to implement left join in JOIN Extension method )
Note that if you're using Entity Framework then you don't need to worry about doing any of this at all! Just use Include:
var query = db.Inbox
.Include( i => i.User )
.Include( i => i.User.Merchandise )
.Include i => i.Merchandise )
.Where( i => i.ToCompanyId = 10 || i.FromCompanyId == 10 );

LINQ: Inner join 2 table + outer join 1 table

I have 2 inner joins (3 tables) but I don't know and I find it hard to implement my research about outer join in LINQ. How do I change the last inner join to outer join, such that column will still join even if the column (Role) is null?
Here's an existing SQL version of this which I want to convert to LINQ:
SELECT dbo.EmployeeAccess.id, dbo.EmployeeAccess.EmpNo, dbo.EmployeeAccess.RoleID, dbo.EmployeeAccess.Active, dbo.EmployeeAccessLevel.Role,
dbo.View_HCM.LNameByFName
FROM dbo.EmployeeAccess LEFT OUTER JOIN
dbo.EmployeeAccessLevel ON dbo.EmployeeAccess.RoleID = dbo.EmployeeAccessLevel.id INNER JOIN
dbo.View_HCM ON dbo.EmployeeAccess.EmpNo = dbo.View_HCM.EmpNo
LINQ I now have with 2 inner joins:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
}
Linq's outer join syntax uses 2 parts. First an into then DefaultIfEmpty
In your case, an outer join might look like this:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
from subjoin in outer_join.DefaultIfEmpty()
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
There are many tutorials on how to create the outer join in LINQ.

LINQ and joining on selects

I have the following SQL:
select o.tekst as Enhet,
coalesce(f.Antall,0) as AntallF,
coalesce(f.snitt,0) as SnittF,
coalesce(b.antall,0) as AntallB
from tblhandlingsplan hp
inner join tblorg o on hp.eierorgid = o.orgid
left outer join (select f.handlingsplanid, count(t.tiltakid) as Antall, coalesce(avg(convert(float,t.status)),0) as Snitt from tblhandlingsplanforbedring f left outer join tblhandlingsplantiltak t on f.forbedringsid = t.forbedringsid group by f.handlingsplanid) f on hp.handlingsplanid = f.handlingsplanid
left outer join (select b.handlingsplanid, count(b.bevaringsid) as Antall from tblhandlingsplanbevaring b group by b.handlingsplanid) b on hp.handlingsplanid = b.handlingsplanid
where utsendingsid = 1
Which works exactly how I want it... Now I'm trying to convert this to LINQ...
I have gotten this far
from h in TblHandlingsplans
join o in TblOrgs
on h.EierOrgID equals o.OrgID
join f in TblHandlingsplanForbedrings
on h.HandlingsplanID equals f.HandlingsplanID into f2
join b in TblHandlingsplanBevarings
on h.HandlingsplanID equals b.HandlingsplanID into b2
where h.UtsendingsID == 1
select new {
Enhet = o.Tekst,
AntallF = f2.Count(),
AntallB = b2.Count()
}
however now I'm stuck... I can't for the life of me figure out how to include the average part from the SQL solution... Any takers?
I'm thinking of shoving the whole thing into a SP and leave it with that...
var query1 = from a in DB.Table1
select new
{
Id = a.Id,
Average = a.B.Average()
};
var query2 = from b in DB.Table2
join c in query1 on b.Id equals c.Id
select c;
Just freehanded it, so it might not actually work, but is that the kind of thing you're trying to do? That would result in a single SQL query being created when query2 was used.

Categories