How do I define JOIN precedence in SqlKata - c#

I'm using SqlKata in my project and it's necessary to connect several tables with the help of nested join. I expect to see something like that:
SELECT * FROM t1
LEFT JOIN (t2 LEFT JOIN t3 ON t3.id = t2.id)
ON t2.id = t1.id
In Join/LeftJoin/RigthJoin methods, I did not find any overloads that would accept anything other than a join or other request.
Wouldn't want to manually make such connections, maybe someone has already faced such a problem? That would be great, I would really appreciate a hint.

Defining JOIN precedence is not available in SqlKata at the moment.
But you can achieve same result by using a Sub Query.
var query = new Query("t1")
.LeftJoin(
new Query("t2").LeftJoin("t3", "t3.id", "t2.id").As("tmp"),
j => j.On( "tmp.id", "t1.id")
);
This query would result in the following sql:
SELECT * FROM [t1] LEFT JOIN (
SELECT * FROM [t2] LEFT JOIN [t3] ON [t3].[id] = [t2].[id]
) AS [tmp] ON ([tmp].[id] = [t1].[id])

Related

linq-to-sql joins with multiple from clauses syntax vs. traditional join syntax

What the difference between writing a join using 2 from clauses and a where like this:
var SomeQuery = from a in MyDC.Table1
from b in MyDC.Table2
where a.SomeCol1 == SomeParameter && a.SomeCol2 === b.SomeCol1
and writing a join using the join operator.
This is for a join on 2 tables but of course, sometimes, we need to join even more tables and we need to combine other from clauses with where if we choose the syntax above.
I know both syntax queries return the same data but I was wondering if there's a performance difference, or another kind of difference, that would conclusively favor one syntax over the other.
Thanks for your suggestions.
This question is actually answered pretty good in these two.
INNER JOIN ON vs WHERE clause
INNER JOIN vs multiple table names in "FROM"
I've included two examples on how three different LINQ expressions will be translated into SQL.
Implicit join:
from prod in Articles
from kat in MainGroups
where kat.MainGroupNo == prod.MainGroupNo
select new { kat.Name, prod.ArticleNo }
Will be translated into
SELECT [t1].[Name], [t0].[ArticleNo]
FROM [dbo].[Article] AS [t0], [dbo].[MainGroup] AS [t1]
WHERE [t1].[MainGroupNo] = [t0].[MainGroupNo]
Inner join:
from prod in Articles
join kat in MainGroups on prod.MainGroupNo equals kat.MainGroupNo
select new { kat.Name, prod.ArticleNo }
Will be translated into
SELECT [t1].[Name], [t0].[ArticleNo]
FROM [dbo].[Article] AS [t0]
INNER JOIN [dbo].[MainGroup] AS [t1] ON [t0].[MainGroupNo] = [t1].[MainGroupNo]
Left outer join:
from prod in Articles
join g1 in MainGroups on prod.MainGroupNo equals g1.MainGroupNo into prodGroup
from kat in prodGroup.DefaultIfEmpty()
select new { kat.Name, prod.ArticleNo }
Will be translated into
SELECT [t1].[Name] AS [Name], [t0].[ArticleNo]
FROM [dbo].[Article] AS [t0]
LEFT OUTER JOIN [dbo].[MainGroup] AS [t1] ON [t0].[MainGroupNo] = [t1].[MainGroupNo]
If you want to test how your expressions will be translated into SQL, I recommend that you try LINQPad. It's an awesome tool for figuring out this kind of stuff.
var result = from a in DB.classA
from b in DB.classB
where a.id.Equals(b.id)
select new{a.b};

2 levels of joins LINQ

I have 3 objects that I need to link together
Parent: TblClients
This will have multiple children of Type TblBusinessLeads , the key between the two is ClientID
Type Lead will have multiple children of type TblFeeBreakouts , the key between the two is LeadID
I have written the following LINQ to get the databack, but it is not coming back (out of memory exception)
from t0 in TblClients
join t1 in TblBusinessLeads on t0.ClientID equals t1.ClientID into t1_join
from t1 in t1_join.DefaultIfEmpty()
join t3 in TblFeeBreakouts on t1.LeadID equals t3.LeadID into t3_join
from t3 in t3_join.DefaultIfEmpty()
orderby
t0.ClientID,
t1.LeadID
select new {
client_data = t0,
business_lead_data = t1_join,
fee_breakout_data = t3_join
}
I am not sure of you can even do this, but the idea seems pretty common. Any help would be greatly appreciated. Thanks
EDIT:
Wow lot of comments. Here goes my answers
I am trying to run the query in LinqPad, thats where the Out of Memory is Occuring
If I look at the SQL generated, it gives me
SELECT [t0].[ClientID], [t0].[ClientName], [t0].[ClientDesc], [t0].[EditedBy], [t0].[EditedDate], [t0].[CreatedBy], [t0].[CreatedDate], [t3].[LeadID], [t3].[InitiativeName], [t3].[Description], [t3].[NewBusNeeds], [t3].[CreativeNeeds], [t3].[IdeationNeeds], [t3].[Comments], [t3].[LossReasons], [t3].[OriginDate], [t3].[DateReceivedAssignment], [t3].[DueDate], [t3].[TimelineNotes], [t3].[PendingCode], [t3].[EstStartDate], [t3].[EstEndDate], [t3].[ExeStartDate], [t3].[ExeEndDate], [t3].[Probable80Total], [t3].[Possible50Total], [t3].[Emerging25Total], [t3].[NoBudget0Total], [t3].[TotalBudget], [t3].[FinancialNotes], [t3].[DollarsRecordFor], [t3].[BizDevContactUserID], [t3].[BizDevContact2UserID], [t3].[SVPContactUserID], [t3].[ClientMgmtContactUserID], [t3].[CMAdditionalContactUserID], [t3].[AdditionalContactUserID], [t3].[CreatorUserID], [t3].[OfficeID], [t3].[ClientID] AS [ClientID2], [t3].[LeadTypeID], [t3].[ActionNeeded], [t3].[ActionDate], [t3].[NewBusDeliveryDate], [t3].[NewBusDesc], [t3].[CreativeDeliveryDate], [t3].[CreativeDesc], [t3].[IdeationDeliveryDate], [t3].[IdeationDesc], [t3].[AltMediaDeliveryDate], [t3].[AltMediaDesc], [t3].[MobileOpsDeliveryDate], [t3].[MobileOpsDesc], [t3].[EventsDeliveryDate], [t3].[EventsDesc], [t3].[Routing], [t3].[RoutingDate], [t3].[Deleted], [t3].[LeadSourceID], [t3].[NatureofLeadID], [t3].[NatureofLeadNotes], [t3].[EditedBy] AS [EditedBy2], [t3].[EditedDate] AS [EditedDate2], [t3].[CreatedBy] AS [CreatedBy2], [t3].[CreatedDate] AS [CreatedDate2], [t3].[ClientContactName], [t3].[ClientContactTitle], [t3].[ReportingYear], (
SELECT COUNT(*)
FROM [tblBusinessLead] AS [t4]
WHERE [t0].[ClientID] = [t4].[ClientID]
) AS [value], [t1].[LeadID] AS [LeadID2]
FROM [tblClient] AS [t0]
LEFT OUTER JOIN [tblBusinessLead] AS [t1] ON [t0].[ClientID] = [t1].[ClientID]
LEFT OUTER JOIN [tblFeeBreakout] AS [t2] ON [t1].[LeadID] = [t2].[LeadID]
LEFT OUTER JOIN [tblBusinessLead] AS [t3] ON [t0].[ClientID] = [t3].[ClientID]
ORDER BY [t0].[ClientID], [t1].[LeadID], [t2].[LeadID], [t2].[FeeTypeID], [t3]. [LeadID]
This returns like 1.2 million rows
There is no mapping in the model becuase the DB has no relationships (they are inferred, no foreign keys or anything like that)
The reason I am using t1_join and t3_join is because if I use t1 or t3, I get the single entity, not the IEnumerable of the object, hence I cant loop over it.
If you have more questions, please ask.
First of all, what possible use could a client have for 1.2 million rows? There is no real good use case for this, so your first step should be figuring out how to filter your results appropriately.
Second, I believe the reason your query is returning OutOfMemoryException is because LinQPad is doing a ToList() or something similar so that I can show the results of the query in the bottom pane. The ToList() is loading all 1.2 million rows into memory. If you ran the query in a regular .Net app, the following will return an IQueryable<> which will not load into memory.
var query =
from t0 in TblClients
join t1 in TblBusinessLeads on t0.ClientID equals t1.ClientID into t1_join
from t1 in t1_join.DefaultIfEmpty()
join t3 in TblFeeBreakouts on t1.LeadID equals t3.LeadID into t3_join
from t3 in t3_join.DefaultIfEmpty()
orderby
t0.ClientID,
t1.LeadID
select new {
client_data = t0,
business_lead_data = t1_join,
fee_breakout_data = t3_join
};
As stated above, it is probably a good idea to setup asociations on these tables, which I did... The LINQ for the result after the association was simple
var clientList = (from a in tblClients
select a).ToList();
From there it was just accessing the properties.

SQL to Linq: RIGHT JOIN in LINQ

anybody can help me to convert some sql query whit right join like this to linq ?
SELECT dbo.FinnTrans.SanadID, dbo.FinnTrans.Date, dbo.FinnAccount.ID AS AccID,
dbo.FinnAccount.FullId, dbo.FinnAccount.Name, SUM(dbo.FinnTrans.Debit) AS TotalDebit,
SUM(dbo.FinnTrans.Credit) AS TotalCredit
FROM dbo.FinnAccount AS FinnAccount_1 LEFT OUTER JOIN
dbo.FinnAccount ON FinnAccount_1.ParentId = dbo.FinnAccount.ID RIGHT OUTER JOIN
dbo.FinnTrans LEFT OUTER JOIN
dbo.FinnAccount AS FinnAccount_2 ON dbo.FinnTrans.AccID = FinnAccount_2.ID ON
FinnAccount_1.ID = FinnAccount_2.ParentId
WHERE (dbo.FinnTrans.FPID = 7) AND (FinnAccount_2.AccLevel = 3)
GROUP BY dbo.FinnTrans.SanadID, dbo.FinnTrans.Date, dbo.FinnAccount.ID,
dbo.FinnAccount.Name, dbo.FinnAccount.FullId
HAVING (dbo.FinnTrans.SanadID = 1)
You can look here: http://www.hookedonlinq.com/OuterJoinSample.ashx as an example of the left outer join. And you can always swap tables to get either left or right
I've taken the liberty of beatifying your TSQL a little.
The last two join conditions appear malformed to me so this TSQL can not be parsed.
SELECT
[t].SanadID
, [t].Date
, [a].ID [AccID]
, [a].FullId
, [a].Name
, SUM([t].Debit) [TotalDebit]
, SUM([t].Credit) [TotalCredit]
FROM
dbo.FinnAccount [a1]
LEFT OUTER JOIN
dbo.FinnAccount [a]
ON [a1].ParentId = [a].ID
RIGHT OUTER JOIN
dbo.FinnTrans [t]
LEFT OUTER JOIN
dbo.FinnAccount [a2]
ON [a].AccID = [a2].ID
ON [a1].ID = [a2].ParentId
WHERE
[t].FPID = 7
AND
[a2].AccLevel = 3
GROUP BY
[t].SanadID
, [t].Date
, [a].ID
, [a].Name
, [a].FullId
HAVING
[t].SanadID = 1

The best way to join in Linq

I was working with the first method below, but then I found the second and want to know the difference and which is best.
What is the difference between:
from a in this.dataContext.reglements
join b in this.dataContext.Clients on a.Id_client equals b.Id
select...
and
from a in this.dataContext.reglements
from b in this.dataContext.Clients
where a.Id_client == b.Id
select...
I created a test case to test out the difference, and in your scenerio it turns out they are the same.
My test example used AdventureWorks but basically there is an association between
Products->CategoryId->Categories
var q = (
from p in Products
from c in Categories
where p.CategoryID==c.CategoryID
select p
);
q.ToList();
Produces this SQL:
SELECT [t0].[ProductID], [t0].[ProductName], [t0].[CategoryID]
FROM [Products] AS [t0], [Categories] AS [t1]
WHERE [t0].[CategoryID] = ([t1].[CategoryID])
var q2 = (
from p in Products
join c in Categories
on p.CategoryID equals c.CategoryID
select p);
q2.ToList();
Produces this sql:
SELECT [t0].[ProductID], [t0].[ProductName], [t0].[CategoryID]
FROM [Products] AS [t0]
INNER JOIN [Categories] AS [t1] ON [t0].[CategoryID] = ([t1].[CategoryID])
The difference between these two syntaxes will be in the way they are translated into SQL. You can trace Entity Framework or LINQ to SQL to determine the SQL:
LINQ to SQL: http://www.reflectionit.nl/Blog/PermaLinkcba15978-c792-44c9-aff2-26dbcc0da81e.aspx
Check the resulting SQL to determine if there are any differences that could affect performance.

Subqueries in linq

I've been trying for a couple of days to write to "translate" this query in LINQ with no success so far. Could you guys please help me? I would also appreciate some explanation to learn actually something out of it.
Here is the T-SQL query:
SELECT R.ResourceID, R.DefaultValue
FROM Resources as R
JOIN
(SELECT [t0].[NameResourceID] AS [ResourceID]
FROM [dbo].[Sectors] AS [t0]
LEFT OUTER JOIN [dbo].[LocalizedResources] AS [t1] ON [t0].[NameResourceID] = [t1].[ResourceID] and [t1].[LanguageID] = 2
WHERE t1.Value IS NULL) AS subQ
ON R.ResourceID = subQ.ResourceID
Thank's
Try something like that :
from r in db.Resources
join subQ in (from t0 in db.Sectors
join t1 in db.LocalizedResources on t0.NameResourceID equals t1.ResourceID
where t1.LanguageId
&& t1.Value == null
select new { ResourceID = t0.NameResourceID }) on r.ResourceID equals subQ.ResourceID
select new { r.ResourceId, r.DefaultValue };

Categories

Resources