question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SQL Generation Steps for OuterApply

See original GitHub issue

Hi,

Shorter version: Found out today that Serenity picks OUTER APPLY clause in its query builder before it goes for LEFT JOIN values in XyzRow.cs class, causing errors (there is a workaround causing more data reads than needed).

Longer version: So in practical terms, if we have a LeftJoin on a property in XyzRow.cs class and want to use that left join in OuterApply to limit data reads, Serenity throws a SQL error:

The multi-part identifier "jLeftJoinedTable.foreign_key_column" could not be bound.

That means, instead of generating a SQL with main tables and Property LeftJoins first e.g. the expected SQL would be:

SELECT * FROM [schema].[main_table] AS T0
LEFT JOIN [schema].[property_table] AS jLeftJoinedTable ON T0.foreign_key_column = jLeftJoinedTable.foreign_key_column
OUTER APPLY
(
	SELECT DISTINCT
		[outer_table].[column_id],
		[outer_table].[column_name],
		[outer_table].[effected_date]
	FROM [schema].[some_other_table] AS [outer_table]
	WHERE jLeftJoinedTable.outer_table_related_id = outer_table.id
)outerTable

The generated code for XyzRow.cs class actually comes out as.

SELECT * FROM [schema].[main_table] AS T0
OUTER APPLY
(
	SELECT DISTINCT
		[outer_table].[column_id],
		[outer_table].[column_name],
		[outer_table].[effected_date]
	FROM [schema].[some_other_table] AS [outer_table]
	WHERE jLeftJoinedTable.outer_table_related_id = outer_table.id
)outerTable
LEFT JOIN [schema].[property_table] AS jLeftJoinedTable ON T0.foreign_key_column = jLeftJoinedTable.foreign_key_column

This causes The multi-part identifier error mentioned above.

The workaround would be to force more data reads than necessary:

[OuterApply("outerTable", @"
	SELECT DISTINCT
		[outer_table].[column_id],
		[outer_table].[column_name],
		[outer_table].[effected_date]
	FROM [schema].[some_other_table] AS [outer_table]
	LEFT JOIN [schema].[a_third_table] AS [unnecessary_joined_table] ON outerTable.column = unnecessary_joined_table.column
	LEFT JOIN [schema].[main_table] AS T1 ON a_third_table.some_column = T1.some_column
	LEFT JOIN [schema].[property_table] AS jLeftJoinedTable ON T1.foreign_key_column = jLeftJoinedTable.foreign_key_column
	WHERE jLeftJoinedTable.outer_table_related_id = outer_table.id
"])
// XyzRow code..

This makes for a painful SQL where we’d want just a setting label etc.

Interestingly, if we bypass List() method of XyzRepository.cs class and instead follow this:

[OuterApply("outerTable", @"
	SELECT DISTINCT
		[outer_table].[column_id],
		[outer_table].[column_name],
		[outer_table].[effected_date]
	FROM [schema].[some_other_table] AS [outer_table]
	WHERE jLeftJoinedTable.outer_table_related_id = outer_table.id
")]
// XyzRow code..

Then in XyzRepository.cs create a method:

List<XyzRow> CustomListMethod()
{

	// Get latest by create datetime descending.
	void action(SqlQuery query)
	{
		query.Distinct(true);
		query.SelectTableFields();
		query.SelectNonTableFields();
		// query.DebugText.Dump("--List OuContractWeeklyActivityEventRow"); <= checked in LINQPad 6
		//query.ToString().Dump("--GetOUsByPostAssignment");
	}

	List<XyzRow> rows = null;
	using (var connection = SqlConnections.NewByKey(fld.ConnectionKey))
	{
		rows = connection.List<XyzRow>(action);		
	}
	return rows;
}

// XyzRepository code...

Then the SQL is correctly generated as:

SELECT * FROM [schema].[main_table] AS T0
LEFT JOIN [schema].[property_table] AS jLeftJoinedTable ON T0.foreign_key_column = jLeftJoinedTable.foreign_key_column
OUTER APPLY
(
	SELECT DISTINCT
		[outer_table].[column_id],
		[outer_table].[column_name],
		[outer_table].[effected_date]
	FROM [schema].[some_other_table] AS [outer_table]
	WHERE jLeftJoinedTable.outer_table_related_id = outer_table.id
)outerTable

Please can this be looked into? Will save us from creating unnecessary CustomList() methods in repositories.

Kind Regards.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
volkanceylancommented, Aug 6, 2020

Please check this commit with a row similar to yours and the test for it:

https://github.com/volkanceylan/Serenity/commit/875fd6dc9c9493ab3b2ecfbcc7401cef227b933d

I got expected results with your outer apply statement. Need to identify what is different with your row.

1reaction
volkanceylancommented, Aug 5, 2020

If your issue is about order, then select a column in left joined table so that the join is included in query before outer apply.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SQL Generation Steps for OuterApply · Issue #5120
Outer apply is just another kind of join (just like LeftJoin, but you can't simply apply OuterApply on a field directly, but only...
Read more >
SQL Server CROSS APPLY and OUTER APPLY
The OUTER APPLY operator returns all the rows from the left table expression irrespective of its match with the right table expression. For ......
Read more >
Understanding SQL Server CROSS APPLY and OUTER ...
In this blog, we'll learn how the APPLY operator differs from regular JOINs. About CROSS APPLY and OUTER APPLY. SQL Server APPLY operator...
Read more >
Using T-SQL CROSS APPLY and OUTER APPLY
To generate CROSS APPLY and OUTER APPLY, you can use the script in Listing 1 to create a simple table containing a single...
Read more >
Advanced SQL: CROSS APPLY and OUTER APPLY
The APPLY operator is similar to the T-SQL JOIN clause as it also allows you to join two tables – for example, you...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found