Skip to content

NH-3944 - Upgrade Remotion.Linq to v2.1 #568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/NHibernate.Test/Linq/CustomQueryModelRewriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ public QueryModelVisitorBase CreateVisitor(VisitorParameters parameters)
}
}

public class CustomVisitor : QueryModelVisitorBase
public class CustomVisitor : NhQueryModelVisitorBase
{
public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index)
{
whereClause.TransformExpressions(new Visitor().VisitExpression);
whereClause.TransformExpressions(new Visitor().Visit);
}

private class Visitor : ExpressionTreeVisitor
private class Visitor : RelinqExpressionVisitor
{
protected override Expression VisitBinaryExpression(BinaryExpression expression)
protected override Expression VisitBinary(BinaryExpression expression)
{
if (
expression.NodeType == ExpressionType.Equal ||
Expand Down Expand Up @@ -82,7 +82,7 @@ protected override Expression VisitBinaryExpression(BinaryExpression expression)
}
}

return base.VisitBinaryExpression(expression);
return base.VisitBinary(expression);
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@
<HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Remotion.Linq, Version=2.1.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
<HintPath>..\packages\Remotion.Linq.2.1.2\lib\net45\Remotion.Linq.dll</HintPath>
</Reference>
<Reference Include="Remotion.Linq.EagerFetching, Version=2.1.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
<HintPath>..\packages\Remotion.Linq.EagerFetching.2.1.0\lib\net45\Remotion.Linq.EagerFetching.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core">
Expand All @@ -103,9 +109,6 @@
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="Remotion.Linq, Version=1.15.15.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
<HintPath>..\packages\Remotion.Linq.1.15.15.0\lib\portable-net45+wp80+wpa81+win\Remotion.Linq.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedAssemblyInfo.cs">
Expand Down Expand Up @@ -3899,4 +3902,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
3 changes: 2 additions & 1 deletion src/NHibernate.Test/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
<package id="Iesi.Collections" version="4.0.1.4000" targetFramework="net461" />
<package id="log4net" version="2.0.7" targetFramework="net461" />
<package id="NUnit" version="3.6.0" targetFramework="net461" />
<package id="Remotion.Linq" version="1.15.15.0" targetFramework="net461" />
<package id="Remotion.Linq" version="2.1.2" targetFramework="net461" />
<package id="Remotion.Linq.EagerFetching" version="2.1.0" targetFramework="net461" />
<package id="System.Linq.Dynamic" version="1.0.7" targetFramework="net461" />
<!-- System.Threading.Tasks.Extensions is required for dynamically loaded Npgsql.dll (Postgresql driver) -->
<package id="System.Threading.Tasks.Extensions" version="4.3.0" targetFramework="net461" />
Expand Down
29 changes: 29 additions & 0 deletions src/NHibernate/Linq/Clauses/NhClauseBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using Remotion.Linq;

namespace NHibernate.Linq.Clauses
{
public abstract class NhClauseBase
{
/// <summary>
/// Accepts the specified visitor.
/// </summary>
/// <param name="visitor">The visitor to accept.</param>
/// <param name="queryModel">The query model in whose context this clause is visited.</param>
/// <param name="index">
/// The index of this clause in the <paramref name="queryModel" />'s
/// <see cref="P:Remotion.Linq.QueryModel.BodyClauses" /> collection.
/// </param>
public void Accept(IQueryModelVisitor visitor, QueryModel queryModel, int index)
{
if (visitor == null) throw new ArgumentNullException(nameof(visitor));
if (queryModel == null) throw new ArgumentNullException(nameof(queryModel));
if (!(visitor is INhQueryModelVisitor nhVisitor))
throw new ArgumentException("Expect visitor to implement INhQueryModelVisitor", nameof(visitor));

Accept(nhVisitor, queryModel, index);
}

protected abstract void Accept(INhQueryModelVisitor visitor, QueryModel queryModel, int index);
}
}
73 changes: 66 additions & 7 deletions src/NHibernate/Linq/Clauses/NhHavingClause.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,78 @@
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.ExpressionTreeVisitors;
using System;
using System.Linq.Expressions;
using Remotion.Linq;
using Remotion.Linq.Clauses;

namespace NHibernate.Linq.Clauses
{
public class NhHavingClause : WhereClause
public class NhHavingClause : NhClauseBase, IBodyClause
{
public NhHavingClause(Expression predicate)
: base(predicate)
Expression _predicate;

/// <summary>
/// Initializes a new instance of the <see cref="T:NhHavingClause" /> class.
/// </summary>
/// <param name="predicate">The predicate used to filter data items.</param>
public NhHavingClause(Expression predicate)
{
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
_predicate = predicate;
}

/// <summary>
/// Gets the predicate, the expression representing the where condition by which the data items are filtered
/// </summary>
public Expression Predicate
{
get { return _predicate; }
set
{
if (value == null) throw new ArgumentNullException(nameof(value));
_predicate = value;
}
}

protected override void Accept(INhQueryModelVisitor visitor, QueryModel queryModel, int index)
{
visitor.VisitNhHavingClause(this, queryModel, index);
}

/// <inheritdoc />
IBodyClause IBodyClause.Clone(CloneContext cloneContext)
{
return Clone(cloneContext);
}

/// <summary>
/// Transforms all the expressions in this clause and its child objects via the given
/// <paramref name="transformation" /> delegate.
/// </summary>
/// <param name="transformation">
/// The transformation object. This delegate is called for each <see cref="T:System.Linq.Expressions.Expression" />
/// within this
/// clause, and those expressions will be replaced with what the delegate returns.
/// </param>
public void TransformExpressions(Func<Expression, Expression> transformation)
{
if (transformation == null) throw new ArgumentNullException(nameof(transformation));
Predicate = transformation(Predicate);
}

public override string ToString()
{
return "having " + FormattingExpressionTreeVisitor.Format(Predicate);
return "having " + Predicate;
}

/// <summary>Clones this clause.</summary>
/// <param name="cloneContext">
/// The clones of all query source clauses are registered with this
/// <see cref="T:Remotion.Linq.Clauses.CloneContext" />.
/// </param>
/// <returns></returns>
public NhHavingClause Clone(CloneContext cloneContext)
{
if (cloneContext == null) throw new ArgumentNullException(nameof(cloneContext));
return new NhHavingClause(Predicate);
}
}
}
}
146 changes: 126 additions & 20 deletions src/NHibernate/Linq/Clauses/NhJoinClause.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,166 @@
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using NHibernate.Linq.Visitors;
using Remotion.Linq;
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.Expressions;

namespace NHibernate.Linq.Clauses
{
/// <summary>
/// All joins are created as outer joins. An optimization in <see cref="WhereJoinDetector"/> finds
/// joins that may be inner joined and calls <see cref="MakeInner"/> on them.
/// <see cref="QueryModelVisitor"/>'s <see cref="QueryModelVisitor.VisitAdditionalFromClause"/> will
/// then emit the correct HQL join.
/// All joins are created as outer joins. An optimization in <see cref="WhereJoinDetector" /> finds
/// joins that may be inner joined and calls <see cref="MakeInner" /> on them.
/// <see cref="QueryModelVisitor" />'s <see cref="QueryModelVisitor.VisitNhJoinClause" /> will
/// then emit the correct HQL join.
/// </summary>
public class NhJoinClause : AdditionalFromClause
public class NhJoinClause : NhClauseBase, IFromClause, IBodyClause
{
Expression _fromExpression;
string _itemName;
System.Type _itemType;

public NhJoinClause(string itemName, System.Type itemType, Expression fromExpression)
: this(itemName, itemType, fromExpression, new NhWithClause[0])
{
}

/// <summary>
/// Initializes a new instance of the <see cref="T:NHibernate.Linq.Clauses.NhJoinClause" /> class.
/// </summary>
/// <param name="itemName">A name describing the items generated by the from clause.</param>
/// <param name="itemType">The type of the items generated by the from clause.</param>
/// <param name="fromExpression">
/// The <see cref="T:System.Linq.Expressions.Expression" /> generating data items for this
/// from clause.
/// </param>
/// <param name="restrictions"></param>
public NhJoinClause(string itemName, System.Type itemType, Expression fromExpression, IEnumerable<NhWithClause> restrictions)
: base(itemName, itemType, fromExpression)
{
Restrictions = new ObservableCollection<NhWithClause>();
foreach (var withClause in restrictions)
Restrictions.Add(withClause);
if (string.IsNullOrEmpty(itemName)) throw new ArgumentException("Value cannot be null or empty.", nameof(itemName));
if (itemType == null) throw new ArgumentNullException(nameof(itemType));
if (fromExpression == null) throw new ArgumentNullException(nameof(fromExpression));

_itemName = itemName;
_itemType = itemType;
_fromExpression = fromExpression;

Restrictions = new ObservableCollection<NhWithClause>(restrictions);
IsInner = false;
}

public ObservableCollection<NhWithClause> Restrictions { get; private set; }
public ObservableCollection<NhWithClause> Restrictions { get; }

public bool IsInner { get; private set; }

public override AdditionalFromClause Clone(CloneContext cloneContext)
public void TransformExpressions(Func<Expression, Expression> transformation)
{
var joinClause = new NhJoinClause(ItemName, ItemType, FromExpression);
if (transformation == null) throw new ArgumentNullException(nameof(transformation));
foreach (var withClause in Restrictions)
withClause.TransformExpressions(transformation);
FromExpression = transformation(FromExpression);
}

/// <summary>
/// Accepts the specified visitor by calling its
/// <see
/// cref="M:Remotion.Linq.IQueryModelVisitor.VisitNhJoinClause(NHibernate.Linq.Clauses.NhJoinClause,Remotion.Linq.QueryModel,System.Int32)" />
/// method.
/// </summary>
/// <param name="visitor">The visitor to accept.</param>
/// <param name="queryModel">The query model in whose context this clause is visited.</param>
/// <param name="index">
/// The index of this clause in the <paramref name="queryModel" />'s
/// <see cref="P:Remotion.Linq.QueryModel.BodyClauses" /> collection.
/// </param>
protected override void Accept(INhQueryModelVisitor visitor, QueryModel queryModel, int index)
{
visitor.VisitNhJoinClause(this, queryModel, index);
}

IBodyClause IBodyClause.Clone(CloneContext cloneContext)
{
return Clone(cloneContext);
}

/// <summary>
/// Gets or sets a name describing the items generated by this from clause.
/// </summary>
/// <remarks>
/// Item names are inferred when a query expression is parsed, and they usually correspond to the variable names
/// present in that expression.
/// However, note that names are not necessarily unique within a <see cref="T:Remotion.Linq.QueryModel" />. Use names
/// only for readability and debugging, not for
/// uniquely identifying <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> objects. To match an
/// <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> with its references, use the
/// <see cref="P:Remotion.Linq.Clauses.Expressions.QuerySourceReferenceExpression.ReferencedQuerySource" /> property
/// rather than the <see cref="P:NHibernate.Linq.Clauses.NhJoinClause.ItemName" />.
/// </remarks>
public string ItemName
{
get { return _itemName; }
set
{
if (string.IsNullOrEmpty(value)) throw new ArgumentException("Value cannot be null or empty.", nameof(value));
_itemName = value;
}
}

/// <summary>
/// Gets or sets the type of the items generated by this from clause.
/// </summary>
/// <note type="warning">
/// Changing the <see cref="P:NHibernate.Linq.Clauses.NhJoinClause.ItemType" /> of a
/// <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> can make all
/// <see cref="T:Remotion.Linq.Clauses.Expressions.QuerySourceReferenceExpression" /> objects that
/// point to that <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> invalid, so the property setter should be used
/// with care.
/// </note>
public System.Type ItemType
{
get { return _itemType; }
set
{
var withClause2 = new NhWithClause(withClause.Predicate);
joinClause.Restrictions.Add(withClause2);
if (value == null) throw new ArgumentNullException(nameof(value));
_itemType = value;
}
}

/// <summary>
/// The expression generating the data items for this from clause.
/// </summary>
public Expression FromExpression
{
get { return _fromExpression; }
set
{
if (value == null) throw new ArgumentNullException(nameof(value));
_fromExpression = value;
}
}

public void CopyFromSource(IFromClause source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
FromExpression = source.FromExpression;
ItemName = source.ItemName;
ItemType = source.ItemType;
}

public NhJoinClause Clone(CloneContext cloneContext)
{
var joinClause = new NhJoinClause(ItemName, ItemType, FromExpression, Restrictions);
cloneContext.QuerySourceMapping.AddMapping(this, new QuerySourceReferenceExpression(joinClause));
return base.Clone(cloneContext);
return joinClause;
}

public void MakeInner()
{
IsInner = true;
}

public override void TransformExpressions(Func<Expression, Expression> transformation)
public override string ToString()
{
foreach (var withClause in Restrictions)
withClause.TransformExpressions(transformation);
base.TransformExpressions(transformation);
return string.Format("join {0} {1} in {2}", ItemType.Name, ItemName, FromExpression);
}
}
}
}
Loading