CheckQuery ( from c in Cooks group c.Weight by c.Name into cooksByName where cooksByName.Min () > 18 select cooksByName.Key, "SELECT [q0].[key] AS [key] FROM (" + "SELECT [t1].[Name] AS [key], MIN([t1].[Weight]) as [a0] FROM [CookTable] AS [t1] "+ "GROUP BY [t1].[Name]) AS [q0] "+ "WHERE ([q0].[a0] > @1)", new CommandParameter ("@1", 18));
Enumerable.Min, Max, Sum, and Average all have some specific overloads for IEnumerable<double>, IEnumerable<int>, and other sequences of primitive types. The SumExpressionNode and AverageExpressionNode parsers explicitly register those overloads for parsing, but the MinExpressionNode and AverageExpressionNode parsers do not. Therefore, calls to those Min and Max overloads might appear as MethodCallExpressions in the QueryModel rather than as result operators.
The reason for this bug is that booleans are automatically converted to integers (because SQL does not support boolean expressions), but the constructor used by the NewExpression still requires a boolean.
var query = from e in QueryFactory.CreateLinqQuery<Order> ()
select e.OrderItems.OrderBy(oi => oi.ID).FirstOrDefault ();
Exception:
SELECT (SELECT TOP (@1) [t1].* FROM [OrderItemView] AS [t1] WHERE ([t0].[ID] = [t1].[OrderID]) ORDER BY [t1].[ID] ASC) AS [value] FROM [OrderView] AS [t0] WHERE ((SELECT TOP (@2) [t2].[ID] FROM [OrderItemView] AS [t2] WHERE ([t0].[ID] = [t2].[OrderID])) IS NOT NULL) @1 = 1 @2 = 1 Test 'Remotion.Data.UnitTests.DomainObjects.Core.Linq.IntegrationTests.SubQueryIntegrationTest.FirstOrDefault_WithEntity_InSelectAndWhere' failed: Remotion.Data.DomainObjects.Persistence.Rdbms.RdbmsProviderException : Error while executing SQL command. ----> System.Data.SqlClient.SqlException : Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. Persistence\Rdbms\RdbmsProvider.cs(313,0): at Remotion.Data.DomainObjects.Persistence.Rdbms.RdbmsProvider.ExecuteReader(IDbCommand command, CommandBehavior behavior) Persistence\Rdbms\DataContainerLoader.cs(120,0): at Remotion.Data.DomainObjects.Persistence.Rdbms.DataContainerLoader.LoadDataContainersFromCommandBuilder(ICommandBuilder commandBuilder, Boolean allowNulls) Persistence\Rdbms\RdbmsProvider.cs(251,0): at Remotion.Data.DomainObjects.Persistence.Rdbms.RdbmsProvider.LoadDataContainers(ICommandBuilder commandBuilder, Boolean allowNulls) Persistence\Rdbms\RdbmsProvider.cs(197,0): at Remotion.Data.DomainObjects.Persistence.Rdbms.RdbmsProvider.ExecuteCollectionQuery(IQuery query) Infrastructure\RootClientTransaction.cs(170,0): at Remotion.Data.DomainObjects.Infrastructure.RootClientTransaction.LoadDataContainersForQuery(IQuery query) ClientTransaction.cs(1547,0): at Remotion.Data.DomainObjects.ClientTransaction.Remotion.Data.DomainObjects.Infrastructure.IDataSource.LoadDataContainersForQuery(IQuery query) Infrastructure\ObjectLoader.cs(142,0): at Remotion.Data.DomainObjects.Infrastructure.ObjectLoader.LoadCollectionQueryResult[T](IQuery query) Queries\QueryManager.cs(131,0): at Remotion.Data.DomainObjects.Queries.QueryManager.GetCollection[T](IQuery query) Queries\QueryManager.cs(100,0): at Remotion.Data.DomainObjects.Queries.QueryManager.GetCollection(IQuery query) Linq\DomainObjectQueryExecutor.cs(171,0): at Remotion.Data.DomainObjects.Linq.DomainObjectQueryExecutor.ExecuteCollection[T](QueryModel queryModel) Clauses\StreamedData\StreamedSequenceInfo.cs(105,0): at Remotion.Data.Linq.Clauses.StreamedData.StreamedSequenceInfo.ExecuteCollectionQueryModel[T](QueryModel queryModel, IQueryExecutor executor) Clauses\StreamedData\StreamedSequenceInfo.cs(95,0): at Remotion.Data.Linq.Clauses.StreamedData.StreamedSequenceInfo.ExecuteQueryModel(QueryModel queryModel, IQueryExecutor executor) QueryModel.cs(287,0): at Remotion.Data.Linq.QueryModel.Execute(IQueryExecutor executor) QueryProviderBase.cs(120,0): at Remotion.Data.Linq.QueryProviderBase.Execute[TResult](Expression expression) QueryableBase.cs(128,0): at Remotion.Data.Linq.QueryableBase`1.GetEnumerator() at System.Linq.Buffer`1..ctor(IEnumerable`1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) DomainObjects\Core\Linq\IntegrationTests\IntegrationTestBase.cs(35,0): at Remotion.Data.UnitTests.DomainObjects.Core.Linq.IntegrationTests.IntegrationTestBase.CheckQueryResult[T](IEnumerable`1 query, ObjectID[] expectedObjectIDs) DomainObjects\Core\Linq\IntegrationTests\SubQueryIntegrationTest.cs(152,0): at Remotion.Data.UnitTests.DomainObjects.Core.Linq.IntegrationTests.SubQueryIntegrationTest.FirstOrDefault_WithEntity_InSelectAndWhere() --SqlException at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlDataReader.ConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior) Tracing\TracingDbCommand.cs(150,0): at Remotion.Data.DomainObjects.Tracing.TracingDbCommand.<>c__DisplayClass3.<ExecuteReader>b__2() Tracing\TracingDbCommand.cs(185,0): at Remotion.Data.DomainObjects.Tracing.TracingDbCommand.ExecuteWithProfiler[T](Func`1 operation) Tracing\TracingDbCommand.cs(150,0): at Remotion.Data.DomainObjects.Tracing.TracingDbCommand.ExecuteReader(CommandBehavior behavior) Persistence\Rdbms\RdbmsProvider.cs(309,0): at Remotion.Data.DomainObjects.Persistence.Rdbms.RdbmsProvider.ExecuteReader(IDbCommand command, CommandBehavior behavior)
To remedy, the subquery should be moved to the FROM part of the surrounding query. Since it only selects a single entity, this will not change the number of result rows.
Support for queries of the following form:
(from c in Cooks
group c.ID by c.Kitchen).All (group => group.Key != null)
[This feature was already released with 1.13.65, but with an invalid description.]
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 VBStringComparisonExpression - deriving from ExtensionExpression - and an IVBSpecificExpressionVisitor 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 for = and <> and to MethodCallExpressions to String.CompareTo for <, <=, >, and >=. Most LINQ providers without VB support will never need to deal with those expressions (ExpressionTreeVisitor will automatically visit the child expression held by the VBStringComparisonExpression, ThrowingExpressionTreeVisitor will automatically reduce by default). LINQ providers with VB support can choose.
The VB transformation is always included, so LINQ providers already handling MethodCallExpressions to VB's CompareString should change their implementation and implement IVBSpecificExpressionVisitor instead.
Simple support for constructs such as:
from x in ... select x from x in ... select x.Name from x in ... select new MyEntity (x.ID, x.FirstName, x.LastName) from x in ... select new { Name = x.Name, Age = 12 } from x in ... select new { x.Name, x.Age }
The projection can be executed in memory by the LINQ provider after the query has been executed against the database by: