Skip to content

Commit

Permalink
NH-3247 - Char value gets 'cached' - fix and test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
fredericDelaporte committed Mar 19, 2017
1 parent 0f88aa1 commit bb28853
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 6 deletions.
11 changes: 11 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3247/Entity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace NHibernate.Test.NHSpecificTest.NH3247
{
class Entity
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual Char Initial { get; set; }
}
}
58 changes: 58 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3247/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Linq;
using NHibernate.Linq;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH3247
{
[TestFixture]
public class Fixture : BugTestCase
{
protected override void OnSetUp()
{
using (ISession session = OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
var e1 = new Entity {Name = "Bob", Initial = 'B' };
session.Save(e1);

var e2 = new Entity {Name = "Sally", Initial = 'S' };
session.Save(e2);

session.Flush();
transaction.Commit();
}
}

protected override void OnTearDown()
{
using (ISession session = OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete("from System.Object");

session.Flush();
transaction.Commit();
}
}

[Test]
public void CharParameterValueShouldNotBeCached()
{
using (ISession session = OpenSession())
using (session.BeginTransaction())
{
var result = session.Query<Entity>()
.Where(e => e.Initial == 'B')
.Single();

Assert.AreEqual('B', result.Initial);

result = session.Query<Entity>()
.Where(e => e.Initial == 'S')
.Single();

Assert.AreEqual('S', result.Initial);
}
}
}
}
10 changes: 10 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/NH3247/Mappings.hbm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test" namespace="NHibernate.Test.NHSpecificTest.NH3247">

<class name="Entity">
<id name="Id" generator="guid.comb" />
<property name="Name" />
<property name="Initial" />
</class>

</hibernate-mapping>
3 changes: 3 additions & 0 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\Fixture.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\FooExample.cs" />
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\IExample.cs" />
<Compile Include="NHSpecificTest\NH3247\Entity.cs" />
<Compile Include="NHSpecificTest\NH3247\Fixture.cs" />
<Compile Include="NHSpecificTest\NH3386\Entity.cs" />
<Compile Include="NHSpecificTest\NH3386\Fixture.cs" />
<Compile Include="NHSpecificTest\NH3961\Entity.cs" />
Expand Down Expand Up @@ -3215,6 +3217,7 @@
<EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="NHSpecificTest\NH3247\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3386\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3961\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3963\Mappings.hbm.xml" />
Expand Down
9 changes: 5 additions & 4 deletions src/NHibernate/Linq/NhLinqExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ public class NhLinqExpression : IQueryExpression

public NhLinqExpression(Expression expression, ISessionFactoryImplementor sessionFactory)
{
_expression = NhPartialEvaluatingExpressionTreeVisitor.EvaluateIndependentSubtrees(expression);
_expression = NhRelinqQueryParser.PreTransform(expression);

// We want logging to be as close as possible to the original expression sent from the
// application. But if we log before partial evaluation, the log won't include e.g.
// subquery expressions if those are defined by the application in a variable referenced
// from the main query.
// application. But if we log before partial evaluation done in PreTransform, the log won't
// include e.g. subquery expressions if those are defined by the application in a variable
// referenced from the main query.
LinqLogging.LogExpression("Expression (partially evaluated)", _expression);

_constantToParameterMap = ExpressionParameterVisitor.Visit(ref _expression, sessionFactory);
Expand Down
23 changes: 21 additions & 2 deletions src/NHibernate/Linq/NhRelinqQueryParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,31 @@
using Remotion.Linq.Parsing.Structure.IntermediateModel;
using Remotion.Linq.Parsing.Structure.NodeTypeProviders;
using Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors;
using NHibernate.Linq.Visitors;

namespace NHibernate.Linq
{
public static class NhRelinqQueryParser
{
private static readonly QueryParser QueryParser;
private static readonly IExpressionTreeProcessor PreProcessor;

static NhRelinqQueryParser()
{
var preTransformerRegistry = new ExpressionTransformerRegistry();
// NH-3247: must remove .Net compiler char to int conversion before
// parameterization occurs.
preTransformerRegistry.Register(new RemoveCharToIntConversion());
PreProcessor = new TransformingExpressionTreeProcessor(preTransformerRegistry);

var transformerRegistry = ExpressionTransformerRegistry.CreateDefault();
transformerRegistry.Register(new RemoveCharToIntConversion());
transformerRegistry.Register(new RemoveRedundantCast());
transformerRegistry.Register(new SimplifyCompareTransformer());

// If needing a compound processor for adding other processing, do not use
// ExpressionTreeParser.CreateDefaultProcessor(transformerRegistry), it would
// cause NH-3961 again by including a PartialEvaluatingExpressionTreeProcessor.
// Directly instanciate a CompoundExpressionTreeProcessor instead.
// Directly instantiate a CompoundExpressionTreeProcessor instead.
var processor = new TransformingExpressionTreeProcessor(transformerRegistry);

var nodeTypeProvider = new NHibernateNodeTypeProvider();
Expand All @@ -39,6 +46,18 @@ static NhRelinqQueryParser()
QueryParser = new QueryParser(expressionTreeParser);
}

/// <summary>
/// Applies the minimal transformations required before parameterization,
/// expression key computing and parsing.
/// </summary>
/// <param name="expression">The expression to transform.</param>
/// <returns>The transformed expression.</returns>
public static Expression PreTransform(Expression expression)
{
var partiallyEvaluatedExpression = NhPartialEvaluatingExpressionTreeVisitor.EvaluateIndependentSubtrees(expression);
return PreProcessor.Process(partiallyEvaluatedExpression);
}

public static QueryModel Parse(Expression expression)
{
return QueryParser.GetParsedQuery(expression);
Expand Down

0 comments on commit bb28853

Please sign in to comment.