Skip to content

Commit 0f77b26

Browse files
committed
NH-3929 - Revert NH-3904
* Users required to explicitly specify custom user type via MappedAs method if they want to use IUserType/ICompositeUser type parameters in Linq queries with generators custom generators, or properly implement generators to take the type into account. * Fix MappedAs method (NH-2401).
1 parent ac7a6f1 commit 0f77b26

File tree

7 files changed

+144
-28
lines changed

7 files changed

+144
-28
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.Data;
3+
using NHibernate.SqlTypes;
4+
using NHibernate.UserTypes;
5+
6+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
7+
{
8+
public class DoubleStringUserType : IUserType
9+
{
10+
public SqlType[] SqlTypes
11+
{
12+
get { return new[] { SqlTypeFactory.GetString(20) }; }
13+
}
14+
15+
public System.Type ReturnedType
16+
{
17+
get { return typeof(string); }
18+
}
19+
20+
public bool IsMutable
21+
{
22+
get { return false; }
23+
}
24+
25+
public int GetHashCode(object x)
26+
{
27+
if (x == null)
28+
{
29+
return 0;
30+
}
31+
return x.GetHashCode();
32+
}
33+
34+
public object NullSafeGet(IDataReader rs, string[] names, object owner)
35+
{
36+
object obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);
37+
if (obj == null)
38+
{
39+
return null;
40+
}
41+
return Convert.ToDouble((string)obj);
42+
}
43+
44+
public void NullSafeSet(IDbCommand cmd, object value, int index)
45+
{
46+
if (value == null)
47+
{
48+
((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
49+
}
50+
else
51+
{
52+
var doubleValue = (double)value;
53+
((IDataParameter)cmd.Parameters[index]).Value = doubleValue.ToString();
54+
}
55+
}
56+
57+
public object DeepCopy(object value)
58+
{
59+
return value;
60+
}
61+
62+
public object Replace(object original, object target, object owner)
63+
{
64+
return original;
65+
}
66+
67+
public object Assemble(object cached, object owner)
68+
{
69+
return cached;
70+
}
71+
72+
public object Disassemble(object value)
73+
{
74+
return value;
75+
}
76+
77+
bool IUserType.Equals(object x, object y)
78+
{
79+
return object.Equals(x, y);
80+
}
81+
}
82+
}

src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/EntityWithUserTypeProperty.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public class EntityWithUserTypeProperty
66
public virtual int Id { get; set; }
77
public virtual string Name { get; set; }
88
public virtual IExample Example { get; set; }
9+
public virtual double DoubleStoredAsString { get; set; }
910
}
1011

1112

src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using NHibernate.Linq;
55
using NUnit.Framework;
66

7-
87
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
98
{
109

@@ -71,7 +70,6 @@ protected override void OnTearDown()
7170
}
7271
}
7372

74-
7573
[Test]
7674
public void EqualityWorksForUserType()
7775
{
@@ -80,14 +78,14 @@ public void EqualityWorksForUserType()
8078
{
8179
var newItem = new BarExample { Value = "Larry" };
8280
var entities = session.Query<EntityWithUserTypeProperty>()
83-
.Where(x=>x.Example == newItem)
81+
.Where(x => x.Example == newItem)
8482
.ToList();
8583

8684
Assert.AreEqual(1, entities.Count);
8785
}
8886
}
8987

90-
[Test]
88+
[Test, Ignore("Not implemented yet")]
9189
public void LinqMethodWorksForUserType()
9290
{
9391
using (var session = OpenSession())
@@ -102,6 +100,50 @@ public void LinqMethodWorksForUserType()
102100
}
103101
}
104102

103+
[Test]
104+
public void EqualityWorksForExplicitUserType()
105+
{
106+
using (var session = OpenSession())
107+
using (session.BeginTransaction())
108+
{
109+
var newItem = new BarExample { Value = "Larry" };
110+
var entities = session.Query<EntityWithUserTypeProperty>()
111+
.Where(x => x.Example == newItem.MappedAs(NHibernateUtil.Custom(typeof(ExampleUserType))))
112+
.ToList();
113+
114+
Assert.AreEqual(1, entities.Count);
115+
}
116+
}
117+
118+
[Test]
119+
public void LinqMethodWorksForExplicitUserType()
120+
{
121+
using (var session = OpenSession())
122+
using (session.BeginTransaction())
123+
{
124+
var newItem = new BarExample { Value = "Larry" };
125+
var entities = session.Query<EntityWithUserTypeProperty>()
126+
.Where(x => x.Example.IsEquivalentTo(newItem.MappedAs(NHibernateUtil.Custom(typeof(ExampleUserType)))))
127+
.ToList();
128+
129+
Assert.AreEqual(2, entities.Count);
130+
}
131+
}
132+
133+
[Test]
134+
public void LinqMethodWorksForStandardStringProperty()
135+
{
136+
using (var session = OpenSession())
137+
using (session.BeginTransaction())
138+
{
139+
var entities = session.Query<EntityWithUserTypeProperty>()
140+
.Where(x => x.Name == "Bob")
141+
.ToList();
142+
143+
Assert.AreEqual(1, entities.Count);
144+
}
145+
}
146+
105147
[Test]
106148
public void CanQueryWithHql()
107149
{

src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Mappings.hbm.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
</id>
77
<property name="Name" />
88
<property name="Example" type="NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators.ExampleUserType, NHibernate.Test" />
9+
<property name="DoubleStoredAsString" type="NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators.DoubleStringUserType, NHibernate.Test" />
910
</class>
10-
</hibernate-mapping>
11+
</hibernate-mapping>

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@
725725
<Compile Include="Linq\ByMethod\DistinctTests.cs" />
726726
<Compile Include="Component\Basic\ComponentWithUniqueConstraintTests.cs" />
727727
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\BarExample.cs" />
728+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\DoubleStringUserType.cs" />
728729
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypeProperty.cs" />
729730
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypePropertyIsEquivalentGenerator.cs" />
730731
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypePropertyGeneratorsRegistry.cs" />

src/NHibernate/Linq/NhLinqExpression.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,13 @@ public class NhLinqExpression : IQueryExpression
3131
public NhLinqExpression(Expression expression, ISessionFactoryImplementor sessionFactory)
3232
{
3333
_expression = NhPartialEvaluatingExpressionTreeVisitor.EvaluateIndependentSubtrees(expression);
34-
3534
// We want logging to be as close as possible to the original expression sent from the
3635
// application. But if we log before partial evaluation, the log won't include e.g.
3736
// subquery expressions if those are defined by the application in a variable referenced
3837
// from the main query.
3938
LinqLogging.LogExpression("Expression (partially evaluated)", _expression);
4039

41-
_constantToParameterMap = ExpressionParameterVisitor.Visit(_expression, sessionFactory);
40+
_constantToParameterMap = ExpressionParameterVisitor.Visit(ref _expression, sessionFactory);
4241

4342
ParameterValuesByName = _constantToParameterMap.Values.ToDictionary(p => p.Name,
4443
p => System.Tuple.Create(p.Value, p.Type));
@@ -77,4 +76,4 @@ internal void CopyExpressionTranslation(NhLinqExpression other)
7776
ParameterDescriptors = other.ParameterDescriptors;
7877
}
7978
}
80-
}
79+
}

src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,21 @@ public class ExpressionParameterVisitor : ExpressionTreeVisitor
2626
ReflectionHelper.GetMethodDefinition(() => Enumerable.Take<object>(null, 0)),
2727
};
2828

29-
private readonly List<CustomType> _allMappedCustomTypes;
30-
3129
public ExpressionParameterVisitor(ISessionFactoryImplementor sessionFactory)
3230
{
3331
_sessionFactory = sessionFactory;
34-
_allMappedCustomTypes = _sessionFactory.GetAllClassMetadata().Values
35-
.SelectMany(c => c.PropertyTypes)
36-
.OfType<CustomType>().ToList();
3732
}
3833

3934
public static IDictionary<ConstantExpression, NamedParameter> Visit(Expression expression, ISessionFactoryImplementor sessionFactory)
35+
{
36+
return Visit(ref expression, sessionFactory);
37+
}
38+
39+
internal static IDictionary<ConstantExpression, NamedParameter> Visit(ref Expression expression, ISessionFactoryImplementor sessionFactory)
4040
{
4141
var visitor = new ExpressionParameterVisitor(sessionFactory);
42-
43-
visitor.VisitExpression(expression);
42+
43+
expression = visitor.VisitExpression(expression);
4444

4545
return visitor._parameters;
4646
}
@@ -49,10 +49,10 @@ protected override Expression VisitMethodCallExpression(MethodCallExpression exp
4949
{
5050
if (expression.Method.Name == "MappedAs" && expression.Method.DeclaringType == typeof(LinqExtensionMethods))
5151
{
52-
var parameter = (ConstantExpression) VisitExpression(expression.Arguments[0]);
53-
var type = (ConstantExpression) expression.Arguments[1];
52+
var parameter = (ConstantExpression)VisitExpression(expression.Arguments[0]);
53+
var type = (ConstantExpression)expression.Arguments[1];
5454

55-
_parameters[parameter].Type = (IType) type.Value;
55+
_parameters[parameter].Type = (IType)type.Value;
5656

5757
return parameter;
5858
}
@@ -94,16 +94,6 @@ protected override Expression VisitConstantExpression(ConstantExpression express
9494
if (expression.Value == null)
9595
type = NHibernateUtil.GuessType(expression.Type);
9696

97-
if (type == null)
98-
{
99-
var customType =
100-
_allMappedCustomTypes.FirstOrDefault(ct => ct.UserType.ReturnedType.IsAssignableFrom(expression.Type));
101-
if (customType != null)
102-
{
103-
type = customType;
104-
}
105-
}
106-
10797
// Constant characters should be sent as strings
10898
if (expression.Type == typeof(char))
10999
{

0 commit comments

Comments
 (0)