Skip to content

Commit ef5e002

Browse files
authored
Fix query dynamic component on unmapped interface (#3154)
Fixes #3150
1 parent bbe7fc9 commit ef5e002

File tree

10 files changed

+104
-52
lines changed

10 files changed

+104
-52
lines changed

src/NHibernate.Test/Async/NHSpecificTest/NH2664Generic/Fixture.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,22 @@ select p
9696
Assert.That(product.Properties["Name"], Is.EqualTo("First Product"));
9797
}
9898
}
99+
100+
[Test(Description = "GH-3150")]
101+
public async Task Query_DynamicComponentByInterfaceAsync()
102+
{
103+
using (var session = OpenSession())
104+
{
105+
var product = await ((
106+
from p in session.Query<IProduct>()
107+
where (string) p.Properties["Name"] == "First Product"
108+
select p
109+
).SingleAsync());
110+
111+
Assert.That(product, Is.Not.Null);
112+
Assert.That(product.Properties["Name"], Is.EqualTo("First Product"));
113+
}
114+
}
99115

100116
[Test]
101117
public async Task Multiple_Query_Does_Not_CacheAsync()
@@ -121,4 +137,4 @@ select p
121137
}
122138
}
123139
}
124-
}
140+
}

src/NHibernate.Test/Async/NHSpecificTest/NH3571Generic/Fixture.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,22 @@ from p in session.Query<Product>()
7777
select p
7878
).SingleAsync());
7979

80+
Assert.That(product, Is.Not.Null);
81+
Assert.That(product.Details.Properties["Name"], Is.EqualTo("First Product"));
82+
}
83+
}
84+
85+
[Test(Description = "GH-3150")]
86+
public async Task CanQueryDynamicComponentInComponentByInterfaceAsync()
87+
{
88+
using (var session = OpenSession())
89+
{
90+
var product = await ((
91+
from p in session.Query<IProduct>()
92+
where (string) p.Details.Properties["Name"] == "First Product"
93+
select p
94+
).SingleAsync());
95+
8096
Assert.That(product, Is.Not.Null);
8197
Assert.That(product.Details.Properties["Name"], Is.EqualTo("First Product"));
8298
}
@@ -106,4 +122,4 @@ select p
106122
}
107123
}
108124
}
109-
}
125+
}

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ select p
8585
Assert.That(product.Properties["Name"], Is.EqualTo("First Product"));
8686
}
8787
}
88+
89+
[Test(Description = "GH-3150")]
90+
public void Query_DynamicComponentByInterface()
91+
{
92+
using (var session = OpenSession())
93+
{
94+
var product = (
95+
from p in session.Query<IProduct>()
96+
where (string) p.Properties["Name"] == "First Product"
97+
select p
98+
).Single();
99+
100+
Assert.That(product, Is.Not.Null);
101+
Assert.That(product.Properties["Name"], Is.EqualTo("First Product"));
102+
}
103+
}
88104

89105
[Test]
90106
public void Multiple_Query_Does_Not_Cache()
@@ -131,4 +147,4 @@ from a in session.Query<Product>()
131147
}
132148
}
133149
}
134-
}
150+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Collections.Generic;
2+
3+
namespace NHibernate.Test.NHSpecificTest.NH2664Generic
4+
{
5+
public interface IProduct
6+
{
7+
string ProductId { get; set; }
8+
IDictionary<string, object> Properties { get; set; }
9+
}
10+
}

src/NHibernate.Test/NHSpecificTest/NH2664Generic/Product.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace NHibernate.Test.NHSpecificTest.NH2664Generic
55
{
6-
public class Product
6+
public class Product : IProduct
77
{
88
public virtual string ProductId { get; set; }
99

@@ -21,4 +21,4 @@ public virtual IDictionary<string, object> Properties
2121
set { _properties = value; }
2222
}
2323
}
24-
}
24+
}

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,22 @@ from p in session.Query<Product>()
6666
select p
6767
).Single();
6868

69+
Assert.That(product, Is.Not.Null);
70+
Assert.That(product.Details.Properties["Name"], Is.EqualTo("First Product"));
71+
}
72+
}
73+
74+
[Test(Description = "GH-3150")]
75+
public void CanQueryDynamicComponentInComponentByInterface()
76+
{
77+
using (var session = OpenSession())
78+
{
79+
var product = (
80+
from p in session.Query<IProduct>()
81+
where (string) p.Details.Properties["Name"] == "First Product"
82+
select p
83+
).Single();
84+
6985
Assert.That(product, Is.Not.Null);
7086
Assert.That(product.Details.Properties["Name"], Is.EqualTo("First Product"));
7187
}
@@ -119,4 +135,4 @@ from a in session.Query<Product>()
119135
}
120136
}
121137
}
122-
}
138+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
3+
namespace NHibernate.Test.NHSpecificTest.NH3571Generic
4+
{
5+
public interface IProduct
6+
{
7+
ProductDetails Details { get; set; }
8+
IList<ProductDetails> DetailsList { get; set; }
9+
string ProductId { get; set; }
10+
}
11+
}

src/NHibernate.Test/NHSpecificTest/NH3571Generic/Product.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace NHibernate.Test.NHSpecificTest.NH3571Generic
55
{
6-
public class Product
6+
public class Product : IProduct
77
{
88
public Product()
99
{
@@ -40,4 +40,4 @@ public virtual IDictionary<string, object> Properties
4040
set { _properties = value; }
4141
}
4242
}
43-
}
43+
}

src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ protected override Expression VisitMethodCall(MethodCallExpression expression)
110110
_collectionParameters.Add(collectionParameter);
111111
}
112112

113-
if (VisitorUtil.IsDynamicComponentDictionaryGetter(expression, _sessionFactory))
113+
if (VisitorUtil.TryGetPotentialDynamicComponentDictionaryMember(expression, out _))
114114
{
115115
return expression;
116116
}

src/NHibernate/Linq/Visitors/VisitorUtil.cs

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,64 +4,31 @@
44
using System.Collections;
55
using System.Reflection;
66
using NHibernate.Util;
7-
using Remotion.Linq.Clauses.Expressions;
87
using Remotion.Linq.Parsing.ExpressionVisitors;
8+
using NHibernate.Engine;
9+
using System;
910

1011
namespace NHibernate.Linq.Visitors
1112
{
1213
public static class VisitorUtil
1314
{
1415
public static bool IsDynamicComponentDictionaryGetter(MethodInfo method, Expression targetObject, IEnumerable<Expression> arguments, ISessionFactory sessionFactory, out string memberName)
1516
{
16-
if (!TryGetPotentialDynamicComponentDictionaryMember(method, targetObject, arguments, out memberName))
17-
{
18-
return false;
19-
}
20-
21-
var member = (MemberExpression) targetObject;
22-
var memberPath = member.Member.Name;
23-
var metaData = sessionFactory.GetClassMetadata(member.Expression.Type);
24-
25-
//Walk backwards if the owning member is not a mapped class (i.e a possible Component)
26-
targetObject = member.Expression;
27-
while (metaData == null && targetObject != null &&
28-
(targetObject.NodeType == ExpressionType.MemberAccess || targetObject.NodeType == ExpressionType.Parameter ||
29-
targetObject is QuerySourceReferenceExpression))
30-
{
31-
System.Type memberType;
32-
if (targetObject is QuerySourceReferenceExpression)
33-
{
34-
var querySourceExpression = (QuerySourceReferenceExpression) targetObject;
35-
memberType = querySourceExpression.Type;
36-
}
37-
else if (targetObject.NodeType == ExpressionType.Parameter)
38-
{
39-
var parameterExpression = (ParameterExpression) targetObject;
40-
memberType = parameterExpression.Type;
41-
}
42-
else //targetObject.NodeType == ExpressionType.MemberAccess
43-
{
44-
var memberExpression = ((MemberExpression) targetObject);
45-
memberPath = memberExpression.Member.Name + "." + memberPath;
46-
memberType = memberExpression.Type;
47-
targetObject = memberExpression.Expression;
48-
}
49-
metaData = sessionFactory.GetClassMetadata(memberType);
50-
}
51-
52-
if (metaData == null)
53-
return false;
54-
55-
// IDictionary can be mapped as collection or component - is it mapped as a component?
56-
var propertyType = metaData.GetPropertyType(memberPath);
57-
return (propertyType != null && propertyType.IsComponentType);
17+
return TryGetPotentialDynamicComponentDictionaryMember(method, targetObject, arguments, out memberName)
18+
&& ExpressionsHelper.TryGetMappedType((ISessionFactoryImplementor) sessionFactory, targetObject, out var mappedType, out _, out _, out _)
19+
// IDictionary can be mapped as collection or component - is it mapped as a component?
20+
&& mappedType.IsComponentType;
5821
}
5922

23+
// Since 5.4
24+
[Obsolete("This method has no more usages and will be removed in a future version")]
6025
public static bool IsDynamicComponentDictionaryGetter(MethodCallExpression expression, ISessionFactory sessionFactory, out string memberName)
6126
{
6227
return IsDynamicComponentDictionaryGetter(expression.Method, expression.Object, expression.Arguments, sessionFactory, out memberName);
6328
}
6429

30+
// Since 5.4
31+
[Obsolete("This method has no more usages and will be removed in a future version")]
6532
public static bool IsDynamicComponentDictionaryGetter(MethodCallExpression expression, ISessionFactory sessionFactory)
6633
{
6734
string memberName;

0 commit comments

Comments
 (0)