Skip to content

Commit

Permalink
Fix for #2283. Added additional Expression types support for OuterApp…
Browse files Browse the repository at this point in the history
…ly queries. (#2289)
  • Loading branch information
sdanyliv committed Jun 21, 2020
1 parent a01510a commit 1078490
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,9 @@ Expression CorrectConditional(IBuildContext context, Expression expr, bool enfor

static bool IsMultipleQuery(MethodCallExpression ce)
{
return typeof(IEnumerable).IsSameOrParentOf(ce.Type) && ce.Type != typeof(string) && !ce.Type.IsArray;
//TODO: Multiply query check should be smarter, possibly not needed if we create fallback mechanism
return !ce.IsQueryable(FirstSingleBuilder.MethodNames) &&
typeof(IEnumerable).IsSameOrParentOf(ce.Type) && ce.Type != typeof(string) && !ce.Type.IsArray;
}

class SubQueryContextInfo
Expand Down
26 changes: 26 additions & 0 deletions Source/LinqToDB/Linq/Builder/ExpressionBuilder.SqlBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,27 @@ public SqlInfo[] ConvertExpressions(IBuildContext context, Expression expression
}
break;
}
case ExpressionType.NewArrayInit:
{
var expr = (NewArrayExpression)expression;
var sql = expr.Expressions
.Select(arg => ConvertExpressions(context, arg, queryConvertFlag, columnDescriptor))
.SelectMany(si => si)
.ToArray();

return sql;
}
case ExpressionType.ListInit:
{
var expr = (ListInitExpression)expression;
var sql = expr.Initializers
.SelectMany(init => init.Arguments)
.Select(arg => ConvertExpressions(context, arg, queryConvertFlag, columnDescriptor))
.SelectMany(si => si)
.ToArray();

return sql;
}
}

var ctx = GetContext(context, expression);
Expand Down Expand Up @@ -3259,6 +3280,11 @@ void CollectParameters(Type forType, MethodBase method, ReadOnlyCollection<Expre
return members.Count > 0;
}

case ExpressionType.NewArrayInit:
case ExpressionType.ListInit:
{
return true;
}
// .Select(p => everything else)
//
default :
Expand Down
6 changes: 6 additions & 0 deletions Tests/Base/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using LinqToDB.Data;
using LinqToDB.Linq;
using LinqToDB.Mapping;
using LinqToDB.Reflection;
using LinqToDB.Tools;
using LinqToDB.Tools.Comparers;

Expand Down Expand Up @@ -928,6 +929,11 @@ protected void AreEqualWithComparer<T>(IEnumerable<T> expected, IEnumerable<T> r
AreEqual(t => t, expected, result, ComparerBuilder.GetEqualityComparer<T>());
}

protected void AreEqualWithComparer<T>(IEnumerable<T> expected, IEnumerable<T> result, Func<MemberAccessor,bool> memberPredicate)
{
AreEqual(t => t, expected, result, ComparerBuilder.GetEqualityComparer<T>(memberPredicate));
}

protected void AreEqual<T>(IEnumerable<T> expected, IEnumerable<T> result, IEqualityComparer<T> comparer)
{
AreEqual(t => t, expected, result, comparer);
Expand Down
38 changes: 27 additions & 11 deletions Tests/Linq/Linq/SelectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

using LinqToDB;
using LinqToDB.Data;
using LinqToDB.Extensions;
using LinqToDB.Reflection;
using LinqToDB.Mapping;
using LinqToDB.SqlQuery;
Expand Down Expand Up @@ -1420,8 +1421,6 @@ select new
[Test]
public void OuterApplyTest([IncludeDataSources(TestProvName.AllPostgreSQL95Plus, TestProvName.AllSqlServer2008Plus, TestProvName.AllOracle12)] string context)
{
// TODO: eager loading
// using (new AllowMultipleQuery())
using (var db = GetDataContext(context))
{
var query =
Expand All @@ -1434,12 +1433,15 @@ select new
Child = c1,
Any = children.Any(),
Child1 = children.Where(c => c.ParentID >= p.ParentID).FirstOrDefault(),
Child2 = children.Where(c => c.ParentID >= 2).Select(c => new { c.ChildID, c.ParentID }).FirstOrDefault()
Child2 = children.Where(c => c.ParentID >= 2).Select(c => new { c.ChildID, c.ParentID }).FirstOrDefault(),
ChildArray = children.Where(c => c.ParentID >= p.ParentID).Select(c => new object[] {c.ChildID, c.ParentID}).FirstOrDefault(),
ChildDictionary1 = children.Where(c => c.ParentID >= p.ParentID).Select(c => new Dictionary<int, int?>{{c.ChildID, c.ParentID}}).FirstOrDefault(),
ChildDictionary2 = children.Where(c => c.ParentID >= p.ParentID).Select(c => new Dictionary<string, int?>{{"ChildID", c.ChildID}, {"ParentID", c.ParentID}}).FirstOrDefault()
};

query = query
.Distinct()
.OrderBy(_ => _.Parent.ParentID);
.Distinct()
.OrderBy(_ => _.Parent.ParentID);


var expectedQuery =
Expand All @@ -1452,17 +1454,31 @@ select new
Child = c1,
Any = children.Any(),
Child1 = children.Where(c => c.ParentID >= p.ParentID).FirstOrDefault(),
Child2 = children.Where(c => c.ParentID >= 2).Select(c => new { c.ChildID, c.ParentID }).FirstOrDefault()
Child2 = children.Where(c => c.ParentID >= 2).Select(c => new { c.ChildID, c.ParentID }).FirstOrDefault(),
ChildArray = children.Where(c => c.ParentID >= p.ParentID).Select(c => new object[] {c.ChildID, c.ParentID}).FirstOrDefault(),
ChildDictionary1 = children.Where(c => c.ParentID >= p.ParentID).Select(c => new Dictionary<int, int?>{{c.ChildID, c.ParentID}}).FirstOrDefault(),
ChildDictionary2 = children.Where(c => c.ParentID >= p.ParentID).Select(c => new Dictionary<string, int?>{{"ChildID", c.ChildID}, {"ParentID", c.ParentID}}).FirstOrDefault()
};

var actual = query.ToArray();

var expected = expectedQuery
.Distinct()
.OrderBy(_ => _.Parent.ParentID)
.ToArray();
var expected = expectedQuery
.Distinct()
.OrderBy(_ => _.Parent.ParentID)
.ToArray();

AreEqual(expected, actual);
AreEqualWithComparer(expected, actual, m => !typeof(Dictionary<,>).IsSameOrParentOf(m.MemberInfo.GetMemberType()));

for (int i = 0; i < actual.Length; i++)
{
var item = actual[i];
if (item.Child1 != null)
{
Assert.That(item.ChildDictionary1[item.Child1.ChildID], Is.EqualTo(item.Child1.ParentID));
Assert.That(item.ChildDictionary2["ChildID"], Is.EqualTo(item.Child1.ChildID));
Assert.That(item.ChildDictionary2["ParentID"], Is.EqualTo(item.Child1.ParentID));
}
}
}
}

Expand Down

0 comments on commit 1078490

Please sign in to comment.