The engine looks at relationships and determines it might result in duplicates, as it doesn't know if the entire resultset is in the projection. It then checks if the sort clause field is present in the projection, and herein lies the problem.
By specifying the case sensitivity on the sortclause, the field itself has no expression. So the engine sees the field, it has no expression and it is present in the projection as-is, so it flags it 'ok', and distinct can be emitted.
To avoid this, use:
var sortClause = CrmRelatieViewFields.VolledigeNaam.ToUpper().Ascending();
(this uses the QuerySpec extension methods)
This will place the UPPER() function call on the field, so this time it does have an expression on it, and therefore the engine will flag it as distinct violating and the query won't have distinct. e.g. this query works fine:
[Test]
public void FetchEntityQueryWithJoinAndDistinctAndCaseInsensitiveSortTest()
{
using(var adapter = new DataAccessAdapter())
{
var qf = new QueryFactory();
var q = qf.Order
.From(QueryTarget.LeftJoin(qf.Customer).On(OrderFields.CustomerId.Equal(CustomerFields.CustomerId)))
.Where(CustomerFields.Country=="USA")
.OrderBy(OrderFields.ShipName.ToUpper().Ascending());
var results = adapter.FetchQuery(q);
Assert.AreEqual(121, results.Count);
}
}
which results in the query:
SELECT [Northwind].[dbo].[Orders].[CustomerID] AS [CustomerId],
[Northwind].[dbo].[Orders].[EmployeeID] AS [EmployeeId],
[Northwind].[dbo].[Orders].[Freight],
[Northwind].[dbo].[Orders].[OrderDate],
[Northwind].[dbo].[Orders].[OrderID] AS [OrderId],
[Northwind].[dbo].[Orders].[RequiredDate],
[Northwind].[dbo].[Orders].[ShipAddress],
[Northwind].[dbo].[Orders].[ShipCity],
[Northwind].[dbo].[Orders].[ShipCountry],
[Northwind].[dbo].[Orders].[ShipName],
[Northwind].[dbo].[Orders].[ShippedDate],
[Northwind].[dbo].[Orders].[ShipPostalCode],
[Northwind].[dbo].[Orders].[ShipRegion],
[Northwind].[dbo].[Orders].[ShipVia]
FROM ([Northwind].[dbo].[Orders]
LEFT JOIN [Northwind].[dbo].[Customers]
ON [Northwind].[dbo].[Orders].[CustomerID] = [Northwind].[dbo].[Customers].[CustomerID])
WHERE (([Northwind].[dbo].[Customers].[Country] = @p1))
ORDER BY UPPER([Northwind].[dbo].[Orders].[ShipName]) ASC
It will postpone the duplicate filtering to the client. This means that if you fetch 1000s of rows, the materializer will be a bit slower as it has to do duplicate filtering on the client.