forked from nhibernate/nhibernate-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add test and fix for NH-2915 and NH-3056
Where clause before fetch request was suppressed when additional clauses were used after fetch request
- Loading branch information
Showing
5 changed files
with
269 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | ||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/EXPLICIT_INTERNAL_MODIFIER/@EntryValue">True</s:Boolean> | ||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/EXPLICIT_PRIVATE_MODIFIER/@EntryValue">True</s:Boolean> | ||
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">False</s:Boolean></wpf:ResourceDictionary> | ||
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">False</s:Boolean> | ||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></s:String> | ||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String></wpf:ResourceDictionary> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
src/NHibernate/Linq/Visitors/SubQueryFromClauseFlattener.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Remotion.Linq; | ||
using Remotion.Linq.Clauses; | ||
using Remotion.Linq.Clauses.ExpressionTreeVisitors; | ||
using Remotion.Linq.Clauses.Expressions; | ||
using Remotion.Linq.EagerFetching; | ||
|
||
namespace NHibernate.Linq.Visitors | ||
{ | ||
public class SubQueryFromClauseFlattener : QueryModelVisitorBase | ||
{ | ||
private static readonly System.Type[] FlattenableResultOperators = new[] | ||
{ | ||
typeof (FetchOneRequest), | ||
typeof (FetchManyRequest), | ||
}; | ||
|
||
public static void ReWrite(QueryModel queryModel) | ||
{ | ||
new SubQueryFromClauseFlattener().VisitQueryModel(queryModel); | ||
} | ||
|
||
public override void VisitAdditionalFromClause(AdditionalFromClause fromClause, QueryModel queryModel, int index) | ||
{ | ||
var subQueryExpression = fromClause.FromExpression as SubQueryExpression; | ||
if (subQueryExpression != null) | ||
FlattenSubQuery(subQueryExpression, fromClause, queryModel, index + 1); | ||
base.VisitAdditionalFromClause(fromClause, queryModel, index); | ||
} | ||
|
||
public override void VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel) | ||
{ | ||
var subQueryExpression = fromClause.FromExpression as SubQueryExpression; | ||
if (subQueryExpression != null) | ||
FlattenSubQuery(subQueryExpression, fromClause, queryModel, 0); | ||
base.VisitMainFromClause(fromClause, queryModel); | ||
} | ||
|
||
private static bool CheckFlattenable(QueryModel subQueryModel) | ||
{ | ||
if (subQueryModel.BodyClauses.OfType<OrderByClause>().Any()) | ||
return false; | ||
|
||
if (subQueryModel.ResultOperators.Count == 0) | ||
return true; | ||
|
||
return HasJustAllFlattenableOperator(subQueryModel.ResultOperators); | ||
} | ||
|
||
private static bool HasJustAllFlattenableOperator(IEnumerable<ResultOperatorBase> resultOperators) | ||
{ | ||
return resultOperators.All(x => FlattenableResultOperators.Contains(x.GetType())); | ||
} | ||
|
||
private static void CopyFromClauseData(FromClauseBase source, FromClauseBase destination) | ||
{ | ||
destination.FromExpression = source.FromExpression; | ||
destination.ItemName = source.ItemName; | ||
destination.ItemType = source.ItemType; | ||
} | ||
|
||
private static void CopyResultOperators(IEnumerable<ResultOperatorBase> resultOperators, QueryModel queryModel) | ||
{ | ||
foreach (var bodyClause in resultOperators) | ||
queryModel.ResultOperators.Add(bodyClause); | ||
} | ||
|
||
private static void FlattenSubQuery(SubQueryExpression subQueryExpression, FromClauseBase fromClause, QueryModel queryModel, int destinationIndex) | ||
{ | ||
if (!CheckFlattenable(subQueryExpression.QueryModel)) | ||
return; | ||
|
||
var mainFromClause = subQueryExpression.QueryModel.MainFromClause; | ||
CopyFromClauseData(mainFromClause, fromClause); | ||
|
||
var innerSelectorMapping = new QuerySourceMapping(); | ||
innerSelectorMapping.AddMapping(fromClause, subQueryExpression.QueryModel.SelectClause.Selector); | ||
queryModel.TransformExpressions((ex => ReferenceReplacingExpressionTreeVisitor.ReplaceClauseReferences(ex, innerSelectorMapping, false))); | ||
|
||
InsertBodyClauses(subQueryExpression.QueryModel.BodyClauses, queryModel, destinationIndex); | ||
CopyResultOperators(subQueryExpression.QueryModel.ResultOperators, queryModel); | ||
|
||
var innerBodyClauseMapping = new QuerySourceMapping(); | ||
innerBodyClauseMapping.AddMapping(mainFromClause, new QuerySourceReferenceExpression(fromClause)); | ||
queryModel.TransformExpressions((ex => ReferenceReplacingExpressionTreeVisitor.ReplaceClauseReferences(ex, innerBodyClauseMapping, false))); | ||
} | ||
|
||
private static void InsertBodyClauses(IEnumerable<IBodyClause> bodyClauses, QueryModel queryModel, int destinationIndex) | ||
{ | ||
foreach (var bodyClause in bodyClauses) | ||
{ | ||
queryModel.BodyClauses.Insert(destinationIndex, bodyClause); | ||
++destinationIndex; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters