Skip to content

Commit 8f05f67

Browse files
authored
Partial fix fetching lazy property after Select in Linq (#3392)
Partial fix of #3356 Fix wrong hql From node detection logic. Query source detection is still broken.
1 parent 782f8d7 commit 8f05f67

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ public async Task TestLinqFetchPropertyAsync()
186186
AssertFetchProperty(person);
187187
}
188188

189+
[Test]
190+
public async Task TestLinqFetchPropertyAfterSelectAsync()
191+
{
192+
using var s = OpenSession();
193+
var owner = await (s.Query<Animal>()
194+
.Select(a => a.Owner)
195+
.Fetch(o => o.Image)
196+
.FirstOrDefaultAsync(o => o.Id == 1));
197+
198+
AssertFetchProperty(owner);
199+
}
200+
189201
private static void AssertFetchProperty(Person person)
190202
{
191203
Assert.That(person, Is.Not.Null);

src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ public void TestLinqFetchProperty()
175175
AssertFetchProperty(person);
176176
}
177177

178+
[Test]
179+
public void TestLinqFetchPropertyAfterSelect()
180+
{
181+
using var s = OpenSession();
182+
var owner = s.Query<Animal>()
183+
.Select(a => a.Owner)
184+
.Fetch(o => o.Image)
185+
.FirstOrDefault(o => o.Id == 1);
186+
187+
AssertFetchProperty(owner);
188+
}
189+
178190
private static void AssertFetchProperty(Person person)
179191
{
180192
Assert.That(person, Is.Not.Null);

src/NHibernate/Linq/IntermediateHqlTree.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,17 @@ public void AddFromClause(HqlTreeNode from)
127127
_root.NodesPreOrder.OfType<HqlFrom>().First().AddChild(from);
128128
}
129129

130+
internal HqlTreeNode GetFromNodeByAlias(string alias) =>
131+
_root.NodesPreOrder
132+
.First(x => x.AstNode.Type == HqlSqlWalker.FROM).Children
133+
.First(x => GetNodeAlias(x) == alias);
134+
135+
private static string GetNodeAlias(HqlTreeNode fromNode) =>
136+
fromNode.Children
137+
.Select(x => x.AstNode)
138+
.First(x => x.Type == HqlSqlWalker.ALIAS)
139+
.Text;
140+
130141
internal HqlRange GetFromRangeClause()
131142
{
132143
return _root.NodesPreOrder.OfType<HqlFrom>().First().Children.OfType<HqlRange>().FirstOrDefault();

src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessFetch.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Linq;
33
using NHibernate.Hql.Ast;
4+
using NHibernate.Hql.Ast.ANTLR;
45
using NHibernate.Persister.Entity;
56
using NHibernate.Type;
67
using Remotion.Linq.EagerFetching;
@@ -21,7 +22,7 @@ public void Process(FetchRequestBase resultOperator, QueryModelVisitor queryMode
2122

2223
public void Process(FetchRequestBase resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree, string sourceAlias)
2324
{
24-
Process(resultOperator, queryModelVisitor, tree, null, sourceAlias);
25+
Process(resultOperator, queryModelVisitor, tree, tree.GetFromNodeByAlias(sourceAlias), sourceAlias);
2526
}
2627

2728
private void Process(
@@ -68,13 +69,12 @@ private void Process(
6869
propType = metadata.GetPropertyType(resultOperator.RelationMember.Name);
6970
}
7071
}
71-
72+
7273
if (propType != null && !propType.IsAssociationType)
7374
{
7475
if (currentNode == null)
7576
{
76-
currentNode = tree.GetFromRangeClause()
77-
?? throw new InvalidOperationException($"Property {resultOperator.RelationMember.Name} cannot be fetched for this type of query.");
77+
throw new InvalidOperationException($"Property {resultOperator.RelationMember.Name} cannot be fetched for this type of query.");
7878
}
7979

8080
currentNode.AddChild(tree.TreeBuilder.Fetch());
@@ -85,12 +85,13 @@ private void Process(
8585
{
8686
if (componentType == null)
8787
{
88-
componentType = propType as ComponentType;
89-
if (componentType == null)
88+
if (!propType.IsComponentType)
9089
{
9190
throw new InvalidOperationException(
9291
$"Property {innerFetch.RelationMember.Name} cannot be fetched from a non component type property {resultOperator.RelationMember.Name}.");
9392
}
93+
94+
componentType = (ComponentType) propType;
9495
}
9596

9697
var subTypeIndex = componentType.GetPropertyIndex(innerFetch.RelationMember.Name);

0 commit comments

Comments
 (0)