Combination of LoadWith() and In() not possible in Query
See original GitHub issueI have a query which crashes when i combine LoadWith with In.
Exception message:
'<>h__TransparentIdentifier0.auv.Status.In(Vertrag, Vertragsänderung)' cannot be converted to SQL.
Stack trace:
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap, ColumnDescriptor columnDescriptor)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertCompare(IBuildContext context, ExpressionType nodeType, Expression left, Expression right)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap, ColumnDescriptor columnDescriptor)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertCompare(IBuildContext context, ExpressionType nodeType, Expression left, Expression right)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSearchCondition(IBuildContext context, Expression expression, List`1 conditions, Boolean isNotExpression)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildWhere(IBuildContext parent, IBuildContext sequence, LambdaExpression condition, Boolean checkForSubQuery, Boolean enforceHaving)
at LinqToDB.Linq.Builder.WhereBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.MethodCallBuilder.BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo)
at LinqToDB.Linq.Builder.WhereBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.MethodCallBuilder.BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo)
at LinqToDB.Linq.Builder.SelectBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.MethodCallBuilder.BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo)
at LinqToDB.Linq.Builder.LoadWithBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.MethodCallBuilder.BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo)
at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]()
at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr)
at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr)
at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache)
at LinqToDB.Linq.ExpressionQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at LinqToDB.LinqExtensions.LoadWithQueryable`2.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
The Query:
(from auv in db.AngebotsUndVertragsdaten
join tp in db.Teilprodukte on auv.Id equals tp.SuperId
where auv.Vertragsbeginn.HasValue
where auv.Vertragsende > beginningOfNextYear
where auv.Status.In(Status.Vertrag, Status.Vertragsänderung)
where tp.Von.HasValue && tp.Von.Value.Year <= thisYear
select auv)
.LoadWith(auv => auv.Ref_Teilprodukte)
.ToList();
If i remove the line
where auv.Status.In(Status.Vertrag, Status.Vertragsänderung)
it works again, or if i Remove the
.LoadWith(auv => auv.Ref_Teilprodukte)
it works again.
So the LoadWith should include the entities of the table i already joined on. This are the generated Queries when i just remove the auv.Status.In line. In the first query Linq2Db double joins on the subtable03 (Teilprodukte). The “tp” join is my join and the “detail” join comes from LoadWith. In the Where Statements the “tp” join is used and in the select the “detail” Join. My guess is that this double join will mess up the “in” and that’s why i get an exception.
-- SqlServer.2012
DECLARE @Vertragsende DateTime2
SET @Vertragsende = '2021-01-01T00:00:00'
DECLARE @p1 Int -- Int32
SET @p1 = 2020
SELECT
[auv].[ID],
[detail].[CURRENCY3],
...
[detail].[CURRENCY2]
FROM
[ADDITIONAL] [auv]
INNER JOIN [SUBTABLE03] [tp] ON [auv].[ID] = [tp].[SUPERID]
INNER JOIN [SUBTABLE03] [detail] ON [auv].[ID] = [detail].[SUPERID]
WHERE
[auv].[DATE6] IS NOT NULL AND
[auv].[DATE8] > @Vertragsende AND
[tp].[DATE2] IS NOT NULL AND
DatePart(year, [tp].[DATE2]) <= @p1
DataConnection: BeforeExecute
-- SqlServer.2012
DECLARE @beginningOfNextYear DateTime2
SET @beginningOfNextYear = '2021-01-01T00:00:00'
DECLARE @thisYear Int -- Int32
SET @thisYear = 2020
SELECT
[auv].[CURRENCY24],
...
[auv].[CURRENCY12]
FROM
[ADDITIONAL] [auv]
INNER JOIN [SUBTABLE03] [tp] ON [auv].[ID] = [tp].[SUPERID]
WHERE
[auv].[DATE6] IS NOT NULL AND
[auv].[DATE8] > @beginningOfNextYear AND
[tp].[DATE2] IS NOT NULL AND
DatePart(year, [tp].[DATE2]) <= @thisYear
I generated an ExpressionTest-Class to this query, but the contents of this class are only this Exception: (Maybe another bug? Because the Query worked.)
Exception in ExpressionTest-Class
System.ArgumentException
Die Zeichenfolge kann keine Länge von 0 (null) haben.
Parametername: oldValue
bei System.String.ReplaceInternal(String oldValue, String newValue)
bei System.String.Replace(String oldValue, String newValue)
bei LinqToDB.Linq.Builder.ExpressionTestGenerator.<>c.<GenerateSourceString>b__27_0(String current, KeyValuePair`2 item) in D:\a\1\s\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:Zeile 928.
bei System.Linq.Enumerable.Aggregate[TSource,TAccumulate](IEnumerable`1 source, TAccumulate seed, Func`3 func)
bei LinqToDB.Linq.Builder.ExpressionTestGenerator.GenerateSourceString(Expression expr) in D:\a\1\s\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:Zeile 899.
bei LinqToDB.Linq.Builder.ExpressionTestGenerator.GenerateSource(Expression expr) in D:\a\1\s\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:Zeile 865.
So if i use the original query, leave the “auv.status.in” part in and just remove the “loadwith” part, this Query is generated:
-- SqlServer.2012
DECLARE @beginningOfNextYear DateTime2
SET @beginningOfNextYear = '2021-01-01T00:00:00'
DECLARE @thisYear Int -- Int32
SET @thisYear = 2020
SELECT
[auv].[CURRENCY24],
...
[auv].[CURRENCY12]
FROM
[ADDITIONAL] [auv]
INNER JOIN [SUBTABLE03] [tp] ON [auv].[ID] = [tp].[SUPERID]
WHERE
[auv].[DATE6] IS NOT NULL AND
[auv].[DATE8] > @beginningOfNextYear AND
[auv].[TEXT3] IN (N'Vertrag', N'Vertragsänderung') AND
[tp].[DATE2] IS NOT NULL AND
DatePart(year, [tp].[DATE2]) <= @thisYear
So he correctly generates the where TEXT3 IN … part. And the ExpressionTest.0.cs Class this Time also worked.
The Navigation Property i used in LoadWith is defined as this:
[LinqToDB.Mapping.Association(ThisKey = nameof(AngebotsUndVertragsdaten.Id), OtherKey = nameof(Teilprodukte.SuperId), CanBeNull = false)]
public IEnumerable<Teilprodukte> Ref_Teilprodukte { get; set; }
Made a short test with linq2db version: 3.0.1, but the Exception remains.
Environment details
linq2db version: 3.0.0 Database Server: SqlServer Operating system: Windows 10 .NET Framework: 4.5.2
Issue Analytics
- State:
- Created 3 years ago
- Comments:11 (6 by maintainers)
Thanks for reporting will try to reproduce.
I see, you have produced duplicates of main records and
LoadWith
made Cartesian explosion on details. Let me see how we can avoid this without performance penalty.