Skip to content

Commit ee0d520

Browse files
authored
Simplify type check in ConditionalProjection (#2535)
Fixes #1180
1 parent bc1484c commit ee0d520

File tree

3 files changed

+58
-37
lines changed

3 files changed

+58
-37
lines changed

src/NHibernate.Test/Async/NHSpecificTest/GH1180/FixtureByCode.cs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010

1111
using NHibernate.Cfg.MappingSchema;
1212
using NHibernate.Criterion;
13+
using NHibernate.Dialect;
1314
using NHibernate.Mapping.ByCode;
1415
using NUnit.Framework;
1516

1617
namespace NHibernate.Test.NHSpecificTest.GH1180
1718
{
1819
using System.Threading.Tasks;
19-
[KnownBug("NH-3847 (GH-1180)")]
20+
//NH-3847
2021
[TestFixture]
2122
public class ByCodeFixtureAsync : TestCaseMappingByCode
2223
{
@@ -27,7 +28,7 @@ protected override HbmMapping GetMappings()
2728
mapper.Class<Entity>(rc =>
2829
{
2930
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
30-
rc.Property(x => x.Name, m => { m.Length(10); });
31+
rc.Property(x => x.Name, m => {m.Type(NHibernateUtil.AnsiString); m.Length(5); });
3132
rc.Property(x => x.Amount, m => { m.Precision(8); m.Scale(2); });
3233
});
3334

@@ -47,6 +48,12 @@ protected override void OnTearDown()
4748
[Test]
4849
public async Task StringTypesAsync()
4950
{
51+
var whenFalse =
52+
Dialect is Oracle8iDialect
53+
//Most dialects allow to return DbType.String and DbType.AnsiString in case statement
54+
//But Oracle throws 'ORA-12704: character set mismatch'
55+
? Projections.Constant("otherstring", NHibernateUtil.AnsiString)
56+
: Projections.Constant("otherstring");
5057
using (var session = OpenSession())
5158
using (var transaction = session.BeginTransaction())
5259
{
@@ -58,88 +65,92 @@ public async Task StringTypesAsync()
5865
await (transaction.CommitAsync());
5966
}
6067

61-
// whenTrue is constant, whenFalse is property -> works even before the fix
68+
// whenTrue is constant, whenFalse is property
6269
using (var session = OpenSession())
6370
{
6471
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
6572

6673
var conditionalProjection = Projections.Conditional(
6774
Restrictions.Not(
6875
Restrictions.Like(nameof(Entity.Name), "B%")),
69-
Projections.Constant("other"),
76+
//Property - ansi string length 5; contstant - string, length 10
77+
whenFalse,
7078
Projections.Property(nameof(Entity.Name)));
7179
tagCriteria.SetProjection(conditionalProjection);
7280

7381
// run query
7482
var results = await (tagCriteria.ListAsync());
7583

76-
Assert.That(results, Is.EquivalentTo(new[] {"other", "Beta", "other"}));
84+
Assert.That(results, Is.EquivalentTo(new[] {"otherstring", "Beta", "otherstring"}));
7785
}
7886

79-
// whenTrue is property, whenFalse is constant -> fails before the fix
87+
// whenTrue is property, whenFalse is constant
8088
using (var session = OpenSession())
8189
{
8290
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
8391

8492
var conditionalProjection = Projections.Conditional(
8593
Restrictions.Like(nameof(Entity.Name), "B%"),
8694
Projections.Property(nameof(Entity.Name)),
87-
Projections.Constant("other"));
95+
whenFalse);
8896
tagCriteria.SetProjection(conditionalProjection);
8997

9098
// run query
9199
var results = await (tagCriteria.ListAsync());
92100

93-
Assert.That(results, Is.EquivalentTo(new[] {"other", "Beta", "other"}));
101+
Assert.That(results, Is.EquivalentTo(new[] {"otherstring", "Beta", "otherstring"}));
94102
}
95103
}
96104

97105
[Test]
98106
public async Task DecimalTypesAsync()
99107
{
108+
//On some dialects (SQLite) Scale mapping is ignored
109+
var propertyResult = TestDialect.HasBrokenDecimalType ? 42.131m : 42.13m;
100110
using (var session = OpenSession())
101111
using (var transaction = session.BeginTransaction())
102112
{
103-
await (session.SaveAsync(new Entity {Amount = 3.14m}));
104-
await (session.SaveAsync(new Entity {Amount = 42.13m}));
105-
await (session.SaveAsync(new Entity {Amount = 17.99m}));
113+
await (session.SaveAsync(new Entity {Amount = 3.141m}));
114+
await (session.SaveAsync(new Entity {Amount = 42.131m}));
115+
await (session.SaveAsync(new Entity {Amount = 17.991m}));
106116

107117
await (transaction.CommitAsync());
108118
}
109119

110-
// whenTrue is constant, whenFalse is property -> works even before the fix
120+
// whenTrue is constant, whenFalse is property
111121
using (var session = OpenSession())
112122
{
113123
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
114124

115125
var conditionalProjection = Projections.Conditional(
116126
Restrictions.Not(
117127
Restrictions.Ge(nameof(Entity.Amount), 20m)),
118-
Projections.Constant(20m),
128+
//Property scale is 2, make sure constant scale 3 is not lost
129+
Projections.Constant(20.123m),
119130
Projections.Property(nameof(Entity.Amount)));
120131
tagCriteria.SetProjection(conditionalProjection);
121132

122133
// run query
123134
var results = await (tagCriteria.ListAsync());
124135

125-
Assert.That(results, Is.EquivalentTo(new[] {20m, 42.13m, 20m}));
136+
Assert.That(results, Is.EquivalentTo(new[] {20.123m, propertyResult, 20.123m}));
126137
}
127138

128-
// whenTrue is property, whenFalse is constant -> fails before the fix
139+
// whenTrue is property, whenFalse is constant
129140
using (var session = OpenSession())
130141
{
131142
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
132143

133144
var conditionalProjection = Projections.Conditional(
134145
Restrictions.Ge(nameof(Entity.Amount), 20m),
135146
Projections.Property(nameof(Entity.Amount)),
136-
Projections.Constant(20m));
147+
Projections.Constant(20.123m));
137148
tagCriteria.SetProjection(conditionalProjection);
138149

139150
// run query
140151
var results = await (tagCriteria.ListAsync());
141152

142-
Assert.That(results, Is.EquivalentTo(new[] {20m, 42.13m, 20m}));
153+
Assert.That(results, Is.EquivalentTo(new[] {20.123m, propertyResult, 20.123m}));
143154
}
144155
}
145156
}

src/NHibernate.Test/NHSpecificTest/GH1180/FixtureByCode.cs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using NHibernate.Cfg.MappingSchema;
22
using NHibernate.Criterion;
3+
using NHibernate.Dialect;
34
using NHibernate.Mapping.ByCode;
45
using NUnit.Framework;
56

67
namespace NHibernate.Test.NHSpecificTest.GH1180
78
{
8-
[KnownBug("NH-3847 (GH-1180)")]
9+
//NH-3847
910
[TestFixture]
1011
public class ByCodeFixture : TestCaseMappingByCode
1112
{
@@ -16,7 +17,7 @@ protected override HbmMapping GetMappings()
1617
mapper.Class<Entity>(rc =>
1718
{
1819
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
19-
rc.Property(x => x.Name, m => { m.Length(10); });
20+
rc.Property(x => x.Name, m => {m.Type(NHibernateUtil.AnsiString); m.Length(5); });
2021
rc.Property(x => x.Amount, m => { m.Precision(8); m.Scale(2); });
2122
});
2223

@@ -36,6 +37,12 @@ protected override void OnTearDown()
3637
[Test]
3738
public void StringTypes()
3839
{
40+
var whenFalse =
41+
Dialect is Oracle8iDialect
42+
//Most dialects allow to return DbType.String and DbType.AnsiString in case statement
43+
//But Oracle throws 'ORA-12704: character set mismatch'
44+
? Projections.Constant("otherstring", NHibernateUtil.AnsiString)
45+
: Projections.Constant("otherstring");
3946
using (var session = OpenSession())
4047
using (var transaction = session.BeginTransaction())
4148
{
@@ -47,88 +54,92 @@ public void StringTypes()
4754
transaction.Commit();
4855
}
4956

50-
// whenTrue is constant, whenFalse is property -> works even before the fix
57+
// whenTrue is constant, whenFalse is property
5158
using (var session = OpenSession())
5259
{
5360
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
5461

5562
var conditionalProjection = Projections.Conditional(
5663
Restrictions.Not(
5764
Restrictions.Like(nameof(Entity.Name), "B%")),
58-
Projections.Constant("other"),
65+
//Property - ansi string length 5; contstant - string, length 10
66+
whenFalse,
5967
Projections.Property(nameof(Entity.Name)));
6068
tagCriteria.SetProjection(conditionalProjection);
6169

6270
// run query
6371
var results = tagCriteria.List();
6472

65-
Assert.That(results, Is.EquivalentTo(new[] {"other", "Beta", "other"}));
73+
Assert.That(results, Is.EquivalentTo(new[] {"otherstring", "Beta", "otherstring"}));
6674
}
6775

68-
// whenTrue is property, whenFalse is constant -> fails before the fix
76+
// whenTrue is property, whenFalse is constant
6977
using (var session = OpenSession())
7078
{
7179
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
7280

7381
var conditionalProjection = Projections.Conditional(
7482
Restrictions.Like(nameof(Entity.Name), "B%"),
7583
Projections.Property(nameof(Entity.Name)),
76-
Projections.Constant("other"));
84+
whenFalse);
7785
tagCriteria.SetProjection(conditionalProjection);
7886

7987
// run query
8088
var results = tagCriteria.List();
8189

82-
Assert.That(results, Is.EquivalentTo(new[] {"other", "Beta", "other"}));
90+
Assert.That(results, Is.EquivalentTo(new[] {"otherstring", "Beta", "otherstring"}));
8391
}
8492
}
8593

8694
[Test]
8795
public void DecimalTypes()
8896
{
97+
//On some dialects (SQLite) Scale mapping is ignored
98+
var propertyResult = TestDialect.HasBrokenDecimalType ? 42.131m : 42.13m;
8999
using (var session = OpenSession())
90100
using (var transaction = session.BeginTransaction())
91101
{
92-
session.Save(new Entity {Amount = 3.14m});
93-
session.Save(new Entity {Amount = 42.13m});
94-
session.Save(new Entity {Amount = 17.99m});
102+
session.Save(new Entity {Amount = 3.141m});
103+
session.Save(new Entity {Amount = 42.131m});
104+
session.Save(new Entity {Amount = 17.991m});
95105

96106
transaction.Commit();
97107
}
98108

99-
// whenTrue is constant, whenFalse is property -> works even before the fix
109+
// whenTrue is constant, whenFalse is property
100110
using (var session = OpenSession())
101111
{
102112
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
103113

104114
var conditionalProjection = Projections.Conditional(
105115
Restrictions.Not(
106116
Restrictions.Ge(nameof(Entity.Amount), 20m)),
107-
Projections.Constant(20m),
117+
//Property scale is 2, make sure constant scale 3 is not lost
118+
Projections.Constant(20.123m),
108119
Projections.Property(nameof(Entity.Amount)));
109120
tagCriteria.SetProjection(conditionalProjection);
110121

111122
// run query
112123
var results = tagCriteria.List();
113124

114-
Assert.That(results, Is.EquivalentTo(new[] {20m, 42.13m, 20m}));
125+
Assert.That(results, Is.EquivalentTo(new[] {20.123m, propertyResult, 20.123m}));
115126
}
116127

117-
// whenTrue is property, whenFalse is constant -> fails before the fix
128+
// whenTrue is property, whenFalse is constant
118129
using (var session = OpenSession())
119130
{
120131
ICriteria tagCriteria = session.CreateCriteria(typeof(Entity));
121132

122133
var conditionalProjection = Projections.Conditional(
123134
Restrictions.Ge(nameof(Entity.Amount), 20m),
124135
Projections.Property(nameof(Entity.Amount)),
125-
Projections.Constant(20m));
136+
Projections.Constant(20.123m));
126137
tagCriteria.SetProjection(conditionalProjection);
127138

128139
// run query
129140
var results = tagCriteria.List();
130141

131-
Assert.That(results, Is.EquivalentTo(new[] {20m, 42.13m, 20m}));
142+
Assert.That(results, Is.EquivalentTo(new[] {20.123m, propertyResult, 20.123m}));
132143
}
133144
}
134145
}

src/NHibernate/Criterion/ConditionalProjection.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ namespace NHibernate.Criterion
55
using Engine;
66
using SqlCommand;
77
using Type;
8-
using Util;
98

109
[Serializable]
1110
public class ConditionalProjection : SimpleProjection
@@ -57,11 +56,11 @@ public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuer
5756
IType[] falseTypes = whenFalse.GetTypes(criteria, criteriaQuery);
5857

5958
bool areEqual = trueTypes.Length == falseTypes.Length;
60-
if (trueTypes.Length == falseTypes.Length)
59+
if (areEqual)
6160
{
6261
for (int i = 0; i < trueTypes.Length; i++)
6362
{
64-
if(trueTypes[i].Equals(falseTypes[i]) == false)
63+
if(trueTypes[i].ReturnedClass != falseTypes[i].ReturnedClass)
6564
{
6665
areEqual = false;
6766
break;

0 commit comments

Comments
 (0)