Skip to content

Commit 588ff1a

Browse files
Jeffrey Beckerjeffreyabecker
authored andcommitted
fix NH3904 -- User Types not being properly captured as constants in linq
expressions.
1 parent 394781b commit 588ff1a

File tree

11 files changed

+368
-0
lines changed

11 files changed

+368
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
4+
{
5+
[Serializable]
6+
public class BarExample : IExample
7+
{
8+
public string Value { get; set; }
9+
public override string ToString()
10+
{
11+
return string.Format("Bar:{0}", Value);
12+
}
13+
public bool IsEquivalentTo(IExample that)
14+
{
15+
return this.Value == that.Value;
16+
}
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Text;
4+
using NHibernate.Mapping.ByCode;
5+
using NHibernate.Mapping.ByCode.Conformist;
6+
7+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
8+
{
9+
public class EntityWithUserTypeProperty
10+
{
11+
public virtual int Id { get; set; }
12+
public virtual string Name { get; set; }
13+
public virtual IExample Example { get; set; }
14+
}
15+
16+
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using NHibernate.Linq;
2+
using NHibernate.Linq.Functions;
3+
4+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
5+
{
6+
public class EntityWithUserTypePropertyGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
7+
{
8+
public EntityWithUserTypePropertyGeneratorsRegistry() : base()
9+
{
10+
RegisterGenerator(ReflectionHelper.GetMethod((IExample e) => e.IsEquivalentTo(null)),
11+
new EntityWithUserTypePropertyIsEquivelentGenerator());
12+
}
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Collections.ObjectModel;
2+
using System.Linq;
3+
using System.Linq.Expressions;
4+
using System.Reflection;
5+
using NHibernate.Hql.Ast;
6+
using NHibernate.Linq;
7+
using NHibernate.Linq.Functions;
8+
using NHibernate.Linq.Visitors;
9+
10+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
11+
{
12+
public class EntityWithUserTypePropertyIsEquivelentGenerator : BaseHqlGeneratorForMethod
13+
{
14+
public EntityWithUserTypePropertyIsEquivelentGenerator() : base()
15+
{
16+
SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition((IExample e) => e.IsEquivalentTo(null)) };
17+
}
18+
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
19+
{
20+
var left = treeBuilder.Cast(visitor.Visit(targetObject).AsExpression(), typeof(string));
21+
var right = treeBuilder.Cast(visitor.Visit(arguments.Cast<Expression>().First()).AsExpression(),
22+
typeof(string));
23+
24+
25+
26+
var leftSubstring = treeBuilder.MethodCall("substring", left, treeBuilder.Constant(4));
27+
var rightSubstring = treeBuilder.MethodCall("substring", right, treeBuilder.Constant(4));
28+
var equals = treeBuilder.Equality(leftSubstring, rightSubstring);
29+
return equals;
30+
}
31+
}
32+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.Text;
5+
using NHibernate.SqlTypes;
6+
using NHibernate.UserTypes;
7+
8+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
9+
{
10+
public class ExampleUserType : IUserType
11+
{
12+
public new bool Equals(object a, object b)
13+
{
14+
IExample ga = a as IExample;
15+
IExample gb = b as IExample;
16+
if (ga == null && gb == null)
17+
{
18+
return true;
19+
}
20+
if (ga != null && gb != null && (ga.GetType() == gb.GetType()))
21+
{
22+
return ga.Value == gb.Value;
23+
}
24+
return false;
25+
}
26+
27+
public int GetHashCode(object x)
28+
{
29+
return ((IExample)x).Value.GetHashCode();
30+
}
31+
32+
public object DeepCopy(object value)
33+
{
34+
if (value == null) return null;
35+
if (value.GetType() == typeof(BarExample))
36+
{
37+
return new BarExample { Value = ((IExample)value).Value };
38+
}
39+
return new FooExample { Value = ((IExample)value).Value };
40+
}
41+
42+
public object Replace(object original, object target, object owner)
43+
{
44+
return original;
45+
}
46+
47+
public object Assemble(object cached, object owner)
48+
{
49+
return cached;
50+
}
51+
52+
public object Disassemble(object value)
53+
{
54+
return value;
55+
}
56+
57+
public SqlType[] SqlTypes { get { return new[] { SqlTypeFactory.GetString(255) }; } }
58+
59+
public System.Type ReturnedType { get { return typeof(IExample); } }
60+
public bool IsMutable { get { return true; } }
61+
62+
public void NullSafeSet(IDbCommand cmd, object value, int index)
63+
{
64+
var dataParameter = (IDataParameter)cmd.Parameters[index];
65+
var example = (IExample)value;
66+
dataParameter.DbType = DbType.String;
67+
if (value == null || example.Value == null)
68+
{
69+
dataParameter.Value = DBNull.Value;
70+
}
71+
else
72+
{
73+
dataParameter.Value = example.ToString();
74+
}
75+
}
76+
77+
public object NullSafeGet(IDataReader rs, string[] names, object owner)
78+
{
79+
var index = rs.GetOrdinal(names[0]);
80+
if (rs.IsDBNull(index))
81+
{
82+
return null;
83+
}
84+
var val = rs.GetString(index);
85+
86+
var parts = val.Split(':');
87+
if (parts[0] == "Bar")
88+
{
89+
return new BarExample { Value = parts[1] };
90+
}
91+
return new FooExample { Value = parts[1] };
92+
}
93+
}
94+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using System;
2+
using System.Collections;
3+
using System.Linq;
4+
using NHibernate.Cfg;
5+
using NHibernate.Dialect;
6+
using NHibernate.Linq;
7+
using NHibernate.Mapping.ByCode;
8+
using NHibernate.Test.NHSpecificTest.FileStreamSql2008;
9+
using NUnit.Framework;
10+
11+
12+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
13+
{
14+
15+
[TestFixture]
16+
public class Fixture : TestCase
17+
{
18+
protected override IList Mappings
19+
{
20+
get { return new[] { "NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators.Mappings.hbm.xml" }; }
21+
}
22+
23+
protected override string MappingsAssembly
24+
{
25+
get { return "NHibernate.Test"; }
26+
}
27+
28+
protected override bool AppliesTo(Dialect.Dialect dialect)
29+
{
30+
return true;
31+
}
32+
33+
protected override void Configure(Configuration cfg)
34+
{
35+
36+
base.Configure(cfg);
37+
cfg.LinqToHqlGeneratorsRegistry<EntityWithUserTypePropertyGeneratorsRegistry>();
38+
}
39+
40+
protected override void OnSetUp()
41+
{
42+
using (var session = OpenSession())
43+
using (var transaction = session.BeginTransaction())
44+
{
45+
var e1 = new EntityWithUserTypeProperty
46+
{
47+
Id = 1,
48+
Name = "Bob",
49+
Example = new BarExample
50+
{
51+
Value = "Larry"
52+
}
53+
};
54+
session.Save(e1);
55+
56+
var e2 = new EntityWithUserTypeProperty
57+
{
58+
Id = 2,
59+
Name = "Sally",
60+
Example = new FooExample
61+
{
62+
Value = "Larry"
63+
}
64+
};
65+
session.Save(e2);
66+
67+
session.Flush();
68+
transaction.Commit();
69+
}
70+
}
71+
72+
protected override void OnTearDown()
73+
{
74+
using (var session = OpenSession())
75+
using (var transaction = session.BeginTransaction())
76+
{
77+
session.Delete("from EntityWithUserTypeProperty");
78+
79+
session.Flush();
80+
transaction.Commit();
81+
}
82+
}
83+
84+
85+
[Test]
86+
public void EqualityWorksForUserType()
87+
{
88+
using (var session = OpenSession())
89+
using (session.BeginTransaction())
90+
{
91+
var newItem = new BarExample { Value = "Larry" };
92+
var entities = session.Query<EntityWithUserTypeProperty>()
93+
.Where(x=>x.Example == newItem)
94+
.ToList();
95+
96+
Assert.AreEqual(1, entities.Count);
97+
}
98+
}
99+
100+
[Test]
101+
public void LinqMethodWorksForUserType()
102+
{
103+
using (var session = OpenSession())
104+
using (session.BeginTransaction())
105+
{
106+
var newItem = new BarExample { Value = "Larry" };
107+
var entities = session.Query<EntityWithUserTypeProperty>()
108+
.Where(x => x.Example.IsEquivalentTo(newItem))
109+
.ToList();
110+
111+
Assert.AreEqual(2, entities.Count);
112+
}
113+
}
114+
[Test]
115+
public void CanQueryWithHQL()
116+
{
117+
using (var session = OpenSession())
118+
using (session.BeginTransaction())
119+
{
120+
var newItem = new BarExample { Value = "Larry" };
121+
var q = session.CreateQuery("from EntityWithUserTypeProperty e where e.Example = :exampleItem");
122+
q.SetParameter("exampleItem", newItem);
123+
var entities = q.List<EntityWithUserTypeProperty>();
124+
125+
Assert.AreEqual(1, entities.Count);
126+
}
127+
}
128+
}
129+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators
4+
{
5+
[Serializable]
6+
public class FooExample : IExample
7+
{
8+
public string Value { get; set; }
9+
public bool IsEquivalentTo(IExample that)
10+
{
11+
return this.Value == that.Value;
12+
}
13+
14+
public override string ToString()
15+
{
16+
return string.Format("Foo:{0}", Value);
17+
}
18+
}
19+
}
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.EntityWithUserTypeCanHaveLinqGenerators
4+
{
5+
6+
public interface IExample
7+
{
8+
string Value { get; set; }
9+
bool IsEquivalentTo(IExample that);
10+
}
11+
}
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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" namespace="NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators" assembly="NHibernate.Test, Version=4.1.0.1001, Culture=neutral, PublicKeyToken=null" xmlns="urn:nhibernate-mapping-2.2">
3+
<class name="EntityWithUserTypeProperty">
4+
<id name="Id" type="Int32">
5+
<generator class="assigned" />
6+
</id>
7+
<property name="Name" />
8+
<property name="Example" type="NHibernate.Test.NHSpecificTest.EntityWithUserTypeCanHaveLinqGenerators.ExampleUserType, NHibernate.Test" />
9+
</class>
10+
</hibernate-mapping>

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,14 @@
723723
<Compile Include="NHSpecificTest\BagWithLazyExtraAndFilter\Fixture.cs" />
724724
<Compile Include="Linq\ByMethod\DistinctTests.cs" />
725725
<Compile Include="Component\Basic\ComponentWithUniqueConstraintTests.cs" />
726+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\BarExample.cs" />
727+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypeProperty.cs" />
728+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypePropertyIsEquivelentGenerator.cs" />
729+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\EntityWithUserTypePropertyGeneratorsRegistry.cs" />
730+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\ExampleUserType.cs" />
731+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\Fixture.cs" />
732+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\FooExample.cs" />
733+
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\IExample.cs" />
726734
<Compile Include="NHSpecificTest\NH3414\Entity.cs" />
727735
<Compile Include="NHSpecificTest\NH3414\FixtureByCode.cs" />
728736
<Compile Include="NHSpecificTest\NH2218\Fixture.cs" />
@@ -3177,6 +3185,7 @@
31773185
</ItemGroup>
31783186
<ItemGroup>
31793187
<EmbeddedResource Include="NHSpecificTest\NH3874\Mappings.hbm.xml" />
3188+
<EmbeddedResource Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\Mappings.hbm.xml" />
31803189
<EmbeddedResource Include="NHSpecificTest\NH2218\Mappings.hbm.xml" />
31813190
<EmbeddedResource Include="NHSpecificTest\NH3046\Mappings.hbm.xml" />
31823191
<EmbeddedResource Include="NHSpecificTest\NH3518\Mappings.hbm.xml" />

0 commit comments

Comments
 (0)