Skip to content

Commit 95d38c1

Browse files
bahusoidhazzik
authored andcommitted
Improve one-to-one handling in queries (#2084)
- Added proper column span calculation (mapping related checks extracted to GetOwnerColumnSpan); - Adjusted OneToOneType to be properly handled as parameter and projection in queries; 1) Allows using one-to-one association in entity comparisons (fixes #1368) 2) Fixes one-to-one handling for composite keys (fixes #1309) 3) Fixes one-to-one projections (fixes #2064, fixes #1125)
1 parent c8b9ae6 commit 95d38c1

File tree

12 files changed

+590
-32
lines changed

12 files changed

+590
-32
lines changed
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
using System;
2+
using System.Linq;
3+
using NHibernate.Cfg.MappingSchema;
4+
using NHibernate.Mapping.ByCode;
5+
using NHibernate.Test.Associations.OneToOneFixtureEntities;
6+
using NUnit.Framework;
7+
8+
namespace NHibernate.Test.Associations
9+
{
10+
[TestFixture]
11+
public class OneToOneFixture : TestCaseMappingByCode
12+
{
13+
[Test]
14+
public void OneToOneCompositeQueryByEntityParam()
15+
{
16+
using (var session = OpenSession())
17+
{
18+
var e = session.Query<EntityWithCompositeId>().FirstOrDefault();
19+
var loadedEntity = session.Query<Parent>().Where(p => p.OneToOneComp == e).FirstOrDefault();
20+
21+
Assert.That(loadedEntity, Is.Not.Null);
22+
}
23+
}
24+
25+
//NH-3778 (GH-1368)
26+
[Test]
27+
public void OneToOneCompositeQueryOverByEntityParam()
28+
{
29+
using (var session = OpenSession())
30+
{
31+
var e = session.Query<EntityWithCompositeId>().FirstOrDefault();
32+
var loadedEntity = session.QueryOver<Parent>().Where(p => p.OneToOneComp == e).SingleOrDefault();
33+
34+
Assert.That(loadedEntity, Is.Not.Null);
35+
}
36+
}
37+
38+
[Test]
39+
public void OneToOneCompositeQueryByKey()
40+
{
41+
using (var session = OpenSession())
42+
{
43+
var e = session.Query<EntityWithCompositeId>().FirstOrDefault();
44+
var loadedEntity = session.Query<Parent>().Where(p => p.OneToOneComp.Key == e.Key).FirstOrDefault();
45+
46+
Assert.That(loadedEntity, Is.Not.Null);
47+
}
48+
}
49+
50+
[Test]
51+
public void OneToOneCompositeQueryOverByKey()
52+
{
53+
using (var session = OpenSession())
54+
{
55+
var e = session.Query<EntityWithCompositeId>().FirstOrDefault();
56+
var loadedEntity = session.QueryOver<Parent>().Where(p => p.OneToOneComp.Key == e.Key).SingleOrDefault();
57+
58+
Assert.That(loadedEntity, Is.Not.Null);
59+
}
60+
}
61+
62+
//NH-3469 (GH-1309)
63+
[Test]
64+
public void OneToOneCompositeQueryByNotNull()
65+
{
66+
using (var session = OpenSession())
67+
{
68+
var loadedEntity = session.Query<Parent>().Where(p => p.OneToOneComp != null).FirstOrDefault();
69+
70+
Assert.That(loadedEntity, Is.Not.Null);
71+
}
72+
}
73+
74+
[Test]
75+
public void OneToOneCompositeQueryOverByNotNull()
76+
{
77+
using (var session = OpenSession())
78+
{
79+
var loadedEntity = session.QueryOver<Parent>().Where(p => p.OneToOneComp != null).SingleOrDefault();
80+
81+
Assert.That(loadedEntity, Is.Not.Null);
82+
}
83+
}
84+
85+
[Test]
86+
public void OneToOneCompositeQueryCompareWithJoin()
87+
{
88+
using (var session = OpenSession())
89+
{
90+
var loadedEntity = session.CreateQuery("select e from Parent p, EntityWithCompositeId e where p.OneToOneComp = e").UniqueResult<EntityWithCompositeId>();
91+
92+
Assert.That(loadedEntity, Is.Not.Null);
93+
}
94+
}
95+
96+
[Explicit("Expression in Restrictions.Where can't recognize direct alias comparison.")]
97+
[Test]
98+
public void OneToOneCompositeQueryOverCompareWithJoin()
99+
{
100+
using(new SqlLogSpy())
101+
using (var session = OpenSession())
102+
{
103+
Parent parent = null;
104+
EntityWithCompositeId oneToOne = null;
105+
106+
var loadedEntity = session.QueryOver<Parent>(() => parent)
107+
.JoinEntityAlias(() => oneToOne, () => parent.OneToOneComp == oneToOne)
108+
.SingleOrDefault();
109+
110+
Assert.That(loadedEntity, Is.Not.Null);
111+
}
112+
}
113+
114+
[Test]
115+
public void OneToOneCompositeQueryOverCompareWithJoinById()
116+
{
117+
using (var session = OpenSession())
118+
{
119+
var e = session.Query<EntityWithCompositeId>().FirstOrDefault();
120+
Parent parent = null;
121+
EntityWithCompositeId oneToOne = null;
122+
123+
var loadedEntity = session.QueryOver<Parent>(() => parent)
124+
.JoinEntityAlias(() => oneToOne, () => parent.OneToOneComp.Key == oneToOne.Key)
125+
.SingleOrDefault();
126+
127+
Assert.That(loadedEntity, Is.Not.Null);
128+
}
129+
}
130+
131+
//GH-2064
132+
[Test]
133+
public void OneToOneCompositeQuerySelectProjection()
134+
{
135+
using (var session = OpenSession())
136+
{
137+
var loadedProjection = session.Query<Parent>().Select(x => new {x.OneToOneComp, x.Key}).FirstOrDefault();
138+
139+
Assert.That(loadedProjection.OneToOneComp, Is.Not.Null);
140+
}
141+
}
142+
143+
//NH-3178 (GH-1125)
144+
[Test]
145+
public void OneToOneQueryOverSelectProjection()
146+
{
147+
using (var session = OpenSession())
148+
{
149+
var loadedEntity = session.QueryOver<Parent>()
150+
.Select(x => x.OneToOneComp)
151+
.SingleOrDefault<EntityWithCompositeId>();
152+
153+
Assert.That(loadedEntity, Is.Not.Null);
154+
}
155+
}
156+
157+
#region Test Setup
158+
159+
protected override HbmMapping GetMappings()
160+
{
161+
var mapper = new ModelMapper();
162+
163+
mapper.Class<EntityWithCompositeId>(
164+
rc =>
165+
{
166+
rc.ComponentAsId(
167+
e => e.Key,
168+
ekm =>
169+
{
170+
ekm.Property(ek => ek.Id1);
171+
ekm.Property(ek => ek.Id2);
172+
});
173+
174+
rc.Property(e => e.Name);
175+
});
176+
177+
mapper.Class<Parent>(
178+
rc =>
179+
{
180+
rc.ComponentAsId(
181+
e => e.Key,
182+
ekm =>
183+
{
184+
ekm.Property(ek => ek.Id1);
185+
ekm.Property(ek => ek.Id2);
186+
});
187+
188+
rc.OneToOne(e => e.OneToOneComp, m => { });
189+
});
190+
191+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
192+
}
193+
194+
protected override void OnTearDown()
195+
{
196+
using (ISession session = OpenSession())
197+
using (ITransaction transaction = session.BeginTransaction())
198+
{
199+
session.Delete("from System.Object");
200+
201+
session.Flush();
202+
transaction.Commit();
203+
}
204+
}
205+
206+
protected override void OnSetUp()
207+
{
208+
using (var session = OpenSession())
209+
using (var transaction = session.BeginTransaction())
210+
{
211+
var key = new CompositeKey
212+
{
213+
Id1 = 4,
214+
Id2 = 3,
215+
};
216+
var oneToOneParent = new Parent()
217+
{
218+
OneToOneComp = new EntityWithCompositeId
219+
{
220+
Key = key,
221+
Name = "Composite2"
222+
},
223+
Key = key
224+
};
225+
226+
session.Save(oneToOneParent.OneToOneComp);
227+
session.Save(oneToOneParent);
228+
229+
session.Flush();
230+
transaction.Commit();
231+
}
232+
}
233+
234+
#endregion Test Setup
235+
}
236+
237+
namespace OneToOneFixtureEntities
238+
{
239+
public class CompositeKey
240+
{
241+
public int Id1 { get; set; }
242+
public int Id2 { get; set; }
243+
244+
public override bool Equals(object obj)
245+
{
246+
var key = obj as CompositeKey;
247+
return key != null
248+
&& Id1 == key.Id1
249+
&& Id2 == key.Id2;
250+
}
251+
252+
public override int GetHashCode()
253+
{
254+
var hashCode = -1596524975;
255+
hashCode = hashCode * -1521134295 + Id1.GetHashCode();
256+
hashCode = hashCode * -1521134295 + Id2.GetHashCode();
257+
return hashCode;
258+
}
259+
}
260+
261+
public class EntityWithCompositeId
262+
{
263+
public virtual CompositeKey Key { get; set; }
264+
public virtual string Name { get; set; }
265+
}
266+
267+
public class OneToOneEntity
268+
{
269+
public virtual Guid Id { get; set; }
270+
public virtual string Name { get; set; }
271+
}
272+
273+
public class Parent
274+
{
275+
public virtual CompositeKey Key { get; set; }
276+
public virtual EntityWithCompositeId OneToOneComp { get; set; }
277+
}
278+
}
279+
}

0 commit comments

Comments
 (0)