Skip to content

Commit fb7dd79

Browse files
NH-3247 - Char value gets 'cached' - fix and test cases
1 parent 0f88aa1 commit fb7dd79

File tree

6 files changed

+108
-6
lines changed

6 files changed

+108
-6
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.NH3247
4+
{
5+
class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
public virtual Char Initial { get; set; }
10+
}
11+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System.Linq;
2+
using NHibernate.Linq;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.NHSpecificTest.NH3247
6+
{
7+
[TestFixture]
8+
public class Fixture : BugTestCase
9+
{
10+
protected override void OnSetUp()
11+
{
12+
using (ISession session = OpenSession())
13+
using (ITransaction transaction = session.BeginTransaction())
14+
{
15+
var e1 = new Entity {Name = "Bob", Initial = 'B' };
16+
session.Save(e1);
17+
18+
var e2 = new Entity {Name = "Sally", Initial = 'S' };
19+
session.Save(e2);
20+
21+
session.Flush();
22+
transaction.Commit();
23+
}
24+
}
25+
26+
protected override void OnTearDown()
27+
{
28+
using (ISession session = OpenSession())
29+
using (ITransaction transaction = session.BeginTransaction())
30+
{
31+
session.Delete("from System.Object");
32+
33+
session.Flush();
34+
transaction.Commit();
35+
}
36+
}
37+
38+
[Test]
39+
public void CharParameterValueShouldNotBeCached()
40+
{
41+
using (ISession session = OpenSession())
42+
using (session.BeginTransaction())
43+
{
44+
var result = session.Query<Entity>()
45+
.Where(e => e.Initial == 'B')
46+
.Single();
47+
48+
Assert.AreEqual('B', result.Initial);
49+
50+
result = session.Query<Entity>()
51+
.Where(e => e.Initial == 'S')
52+
.Single();
53+
54+
Assert.AreEqual('S', result.Initial);
55+
}
56+
}
57+
}
58+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test" namespace="NHibernate.Test.NHSpecificTest.NH3247">
3+
4+
<class name="Entity">
5+
<id name="Id" generator="guid.comb" />
6+
<property name="Name" />
7+
<property name="Initial" column="`Initial`"/>
8+
</class>
9+
10+
</hibernate-mapping>

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,8 @@
736736
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\Fixture.cs" />
737737
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\FooExample.cs" />
738738
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\IExample.cs" />
739+
<Compile Include="NHSpecificTest\NH3247\Entity.cs" />
740+
<Compile Include="NHSpecificTest\NH3247\Fixture.cs" />
739741
<Compile Include="NHSpecificTest\NH3386\Entity.cs" />
740742
<Compile Include="NHSpecificTest\NH3386\Fixture.cs" />
741743
<Compile Include="NHSpecificTest\NH3961\Entity.cs" />
@@ -3215,6 +3217,7 @@
32153217
<EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" />
32163218
</ItemGroup>
32173219
<ItemGroup>
3220+
<EmbeddedResource Include="NHSpecificTest\NH3247\Mappings.hbm.xml" />
32183221
<EmbeddedResource Include="NHSpecificTest\NH3386\Mappings.hbm.xml" />
32193222
<EmbeddedResource Include="NHSpecificTest\NH3961\Mappings.hbm.xml" />
32203223
<EmbeddedResource Include="NHSpecificTest\NH3963\Mappings.hbm.xml" />

src/NHibernate/Linq/NhLinqExpression.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ public class NhLinqExpression : IQueryExpression
3030

3131
public NhLinqExpression(Expression expression, ISessionFactoryImplementor sessionFactory)
3232
{
33-
_expression = NhPartialEvaluatingExpressionTreeVisitor.EvaluateIndependentSubtrees(expression);
33+
_expression = NhRelinqQueryParser.PreTransform(expression);
34+
3435
// We want logging to be as close as possible to the original expression sent from the
35-
// application. But if we log before partial evaluation, the log won't include e.g.
36-
// subquery expressions if those are defined by the application in a variable referenced
37-
// from the main query.
36+
// application. But if we log before partial evaluation done in PreTransform, the log won't
37+
// include e.g. subquery expressions if those are defined by the application in a variable
38+
// referenced from the main query.
3839
LinqLogging.LogExpression("Expression (partially evaluated)", _expression);
3940

4041
_constantToParameterMap = ExpressionParameterVisitor.Visit(ref _expression, sessionFactory);

src/NHibernate/Linq/NhRelinqQueryParser.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,31 @@
1313
using Remotion.Linq.Parsing.Structure.IntermediateModel;
1414
using Remotion.Linq.Parsing.Structure.NodeTypeProviders;
1515
using Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors;
16+
using NHibernate.Linq.Visitors;
1617

1718
namespace NHibernate.Linq
1819
{
1920
public static class NhRelinqQueryParser
2021
{
2122
private static readonly QueryParser QueryParser;
23+
private static readonly IExpressionTreeProcessor PreProcessor;
2224

2325
static NhRelinqQueryParser()
2426
{
27+
var preTransformerRegistry = new ExpressionTransformerRegistry();
28+
// NH-3247: must remove .Net compiler char to int conversion before
29+
// parameterization occurs.
30+
preTransformerRegistry.Register(new RemoveCharToIntConversion());
31+
PreProcessor = new TransformingExpressionTreeProcessor(preTransformerRegistry);
32+
2533
var transformerRegistry = ExpressionTransformerRegistry.CreateDefault();
26-
transformerRegistry.Register(new RemoveCharToIntConversion());
2734
transformerRegistry.Register(new RemoveRedundantCast());
2835
transformerRegistry.Register(new SimplifyCompareTransformer());
2936

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

3643
var nodeTypeProvider = new NHibernateNodeTypeProvider();
@@ -39,6 +46,18 @@ static NhRelinqQueryParser()
3946
QueryParser = new QueryParser(expressionTreeParser);
4047
}
4148

49+
/// <summary>
50+
/// Applies the minimal transformations required before parameterization,
51+
/// expression key computing and parsing.
52+
/// </summary>
53+
/// <param name="expression">The expression to transform.</param>
54+
/// <returns>The transformed expression.</returns>
55+
public static Expression PreTransform(Expression expression)
56+
{
57+
var partiallyEvaluatedExpression = NhPartialEvaluatingExpressionTreeVisitor.EvaluateIndependentSubtrees(expression);
58+
return PreProcessor.Process(partiallyEvaluatedExpression);
59+
}
60+
4261
public static QueryModel Parse(Expression expression)
4362
{
4463
return QueryParser.GetParsedQuery(expression);

0 commit comments

Comments
 (0)