Skip to content

Commit 33f1962

Browse files
fredericDelaportehazzik
authored andcommitted
NH-3950 - Fix failure of FutureValue on First/Single result operator (#555)
1 parent 1c05dcf commit 33f1962

File tree

5 files changed

+152
-37
lines changed

5 files changed

+152
-37
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.NH3950
4+
{
5+
class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
}
10+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using System.Linq;
2+
using NHibernate.Linq;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.NHSpecificTest.NH3950
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"};
16+
session.Save(e1);
17+
18+
var e2 = new Entity {Name = "Sally"};
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 FirstFutureValue()
40+
{
41+
using (ISession session = OpenSession())
42+
using (session.BeginTransaction())
43+
{
44+
var result = session.Query<Entity>()
45+
.OrderBy(e => e.Name)
46+
.ToFutureValue(q => q.First());
47+
48+
Assert.AreEqual("Bob", result.Value.Name);
49+
}
50+
}
51+
52+
[Test]
53+
public void FirstOrDefaultFutureValue()
54+
{
55+
using (ISession session = OpenSession())
56+
using (session.BeginTransaction())
57+
{
58+
var result = session.Query<Entity>()
59+
.Select(e => e.Name)
60+
.OrderBy(n => n)
61+
.ToFutureValue(q => q.FirstOrDefault());
62+
63+
Assert.AreEqual("Bob", result.Value);
64+
}
65+
}
66+
67+
[Test]
68+
public void SingleFutureValue()
69+
{
70+
using (ISession session = OpenSession())
71+
using (session.BeginTransaction())
72+
{
73+
var result = session.Query<Entity>()
74+
.Where(e => e.Name == "Bob")
75+
.ToFutureValue(q => q.Single());
76+
77+
Assert.AreEqual("Bob", result.Value.Name);
78+
}
79+
}
80+
81+
[Test]
82+
public void SingleOrDefaultFutureValue()
83+
{
84+
using (ISession session = OpenSession())
85+
using (session.BeginTransaction())
86+
{
87+
var result = session.Query<Entity>()
88+
.Select(e => e.Name)
89+
.Where(n => n == "Bob")
90+
.ToFutureValue(q => q.SingleOrDefault());
91+
92+
Assert.AreEqual("Bob", result.Value);
93+
}
94+
}
95+
}
96+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test" namespace="NHibernate.Test.NHSpecificTest.NH3950">
3+
4+
<class name="Entity">
5+
<id name="Id" generator="guid.comb" />
6+
<property name="Name" />
7+
</class>
8+
9+
</hibernate-mapping>

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,8 @@
737737
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\Fixture.cs" />
738738
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\FooExample.cs" />
739739
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\IExample.cs" />
740+
<Compile Include="NHSpecificTest\NH3950\Entity.cs" />
741+
<Compile Include="NHSpecificTest\NH3950\Fixture.cs" />
740742
<Compile Include="NHSpecificTest\NH3952\Entity.cs" />
741743
<Compile Include="NHSpecificTest\NH3952\Fixture.cs" />
742744
<Compile Include="NHSpecificTest\NH2204\Model.cs" />
@@ -3206,6 +3208,7 @@
32063208
<EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" />
32073209
</ItemGroup>
32083210
<ItemGroup>
3211+
<EmbeddedResource Include="NHSpecificTest\NH3950\Mappings.hbm.xml" />
32093212
<EmbeddedResource Include="NHSpecificTest\NH3952\Mappings.hbm.xml" />
32103213
<EmbeddedResource Include="NHSpecificTest\NH2204\Mappings.hbm.xml" />
32113214
<EmbeddedResource Include="NHSpecificTest\NH3874\Mappings.hbm.xml" />

src/NHibernate/Impl/FutureValue.cs

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,44 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4+
using System.Linq;
45

56
namespace NHibernate.Impl
67
{
7-
internal class FutureValue<T> : IFutureValue<T>, IDelayedValue
8-
{
9-
public delegate IEnumerable<T> GetResult();
10-
11-
private readonly GetResult getResult;
12-
13-
public FutureValue(GetResult result)
14-
{
15-
getResult = result;
16-
}
17-
18-
public T Value
19-
{
20-
get
21-
{
22-
var result = getResult();
8+
internal class FutureValue<T> : IFutureValue<T>, IDelayedValue
9+
{
10+
public delegate IEnumerable<T> GetResult();
11+
12+
private readonly GetResult getResult;
13+
14+
public FutureValue(GetResult result)
15+
{
16+
getResult = result;
17+
}
18+
19+
public T Value
20+
{
21+
get
22+
{
23+
var result = getResult();
24+
if (ExecuteOnEval != null)
25+
// When not null, ExecuteOnEval is fetched with PostExecuteTransformer from IntermediateHqlTree
26+
// through ExpressionToHqlTranslationResults, which requires a IQueryable as input and directly
27+
// yields the scalar result when the query is scalar.
28+
return (T)ExecuteOnEval.DynamicInvoke(result.AsQueryable());
29+
2330
var enumerator = result.GetEnumerator();
2431

2532
if (!enumerator.MoveNext())
26-
{
27-
var defVal = default(T);
28-
if (ExecuteOnEval != null)
29-
defVal = (T)ExecuteOnEval.DynamicInvoke(defVal);
30-
return defVal;
31-
}
32-
33-
var val = enumerator.Current;
34-
35-
if (ExecuteOnEval != null)
36-
val = (T)ExecuteOnEval.DynamicInvoke(val);
37-
38-
return val;
39-
}
40-
}
41-
42-
public Delegate ExecuteOnEval
43-
{
44-
get; set;
45-
}
46-
}
33+
return default(T);
34+
35+
return enumerator.Current;
36+
}
37+
}
38+
39+
public Delegate ExecuteOnEval
40+
{
41+
get; set;
42+
}
43+
}
4744
}

0 commit comments

Comments
 (0)