Instead, there is now a single API called ReplaceItemsWithoutNotifications which describes what the operation does, not what it is used for. It should be overridden if a derived collection holds custom state, and the custom state must be recalculated when the API is called. ReplaceItemsWithoutNotifications is called by changed end points when the associated transaction is rolled back.
When the transaction is committed, no API is called any more. The DomainObjectCollection.Commit API was previously called on the original value collection when the transaction was committed, but now the original value collection is no longer retained but instantiated on demand.
In SQL, substatements cannot hold ORDER BY clauses. In LINQ, however, subqueries with ordering expressions can easily be constructed:
from o in Orders from oi in ( from item in OrderItems where item.Order == o orderby item.Product select item.Description ) select oi
The problem gets worse because we sometimes construct subqueries even though the user didn't write one, e.g., to handle incompatible result operators, to implement DefaultIfEmpty, etc.
The solution would be to:
The problem is that pulling out the orderings from the subquery is not generally possible unless the select projection is also changed:
from o in Orders
from oi in (
from item in OrderItems
where item.Order == o
select item.Description
)
orderby item.Product // does not work, item is not known in this query
select oi
from o in Orders from oi in ( from item in OrderItems where item.Order == o select new { item.Description, item.Product } ) orderby oi.Product // does not work, item is not known in this query select oi.Description
This is a transformation that requires support for compound projections.
To keep the solution simple, we can pull out orderings only from subqueries we create in result operator handlers and throw an exception for orderings in subqueries the user wrote (unless it is safe to remove or keep them due to Count, Distinct, aggregations, or Top). That would be easier because in the first case, we control all references to the subquery, whereas we'd have to substitute existing references to the subquery in the second case. A full solution requires handling of all subqueries, however.
This issue also affects eager fetching; currently, eager fetching produces fetch query models that cannot be translated to SQL if the original query model contained an OrderByClause.
Conception needed.
By default, ThrowingExpressionTreeVisitor will throw an exception when an expression is encountered that is not handled by the specific visitor subclass. Until now, this would also happen for reducible expressions.
Reducible expressions are extension expressions whose CanReduce property returns true. When the Reduce method is called on such an expression, it returns another expression with (mostly) equal semantics. For example, a VBCompareExpression would return a BinaryExpression with the same comparison semantics (but missing the VB-specific information).
With this change, ThrowingExpressionVisitors will now automatically reduce such expressions and try to visit the reduced form before throwing an exception, thus taking a second chance on the expression tree being visited.
Since the exception case usually means that the provider cannot handle the expression tree, this change should not break anything, but provide a convenient feature for dealing with reducible extension expressions.
VB.NET has a very specific way of dealing with some operators, most notably string comparisons. The method call chain produced for an expression of
From c In Contacts _
Where c.FirstName = "Hugo" _
Select c
is
Contacts
.Where (c => (Operators.CompareString (c.FirstName, "Hugo", False) == 0))
.Select (c => c)
Therefore, the WhereClause produced by re-linq contains a Predicate with a MethodCallExpression invoking VisualBasic's CompareString method, whose result is then compared to 0.
A similar behavior occurs with many operators on other data types as well, such as Add or GreaterThan, but for thise, VB.NET does not produce MethodCallExpressions. Instead, annotated BinaryExpressions (with a MethodInfo indicating the operation) are created, so LINQ providers won't even notice the difference.
However, the VB operators do have very specific semantics; for example, VB compares Nothing and "" to equal (C# does not). Some LINQ providers might want to honor these semantics, others might not want to do so. LINQ-to-SQL does honor the semantics in part - if one side of a string comparison is a constant Nothing, it compares to string.Empty instead in the database.
To enable LINQ providers to deal with VB.NET specifics, this feature introduces a new custom expression hierarchy - deriving from a new class VBExpression - and an IVBExpressionVisitor interface. It uses the extension expression approach, which allows VB expressions to be visited by classes implementing IVBExpressionVisitor. The VB expressions are reduced to ordinary BinaryExpressions (with a MethodInfo hinting at the original operator), so LINQ providers without VB support will never need to deal with those expressions (use automatic reduce). LINQ providers with VB support can choose.
The VB transformation is included by default, but it can be removed by the LINQ provider if necessary.