Skip to content

Commit ac5e2b6

Browse files
authored
Fix Contains subquery with parameter (#3220)
Fixes #3218
1 parent cc13153 commit ac5e2b6

File tree

4 files changed

+236
-7
lines changed

4 files changed

+236
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System;
12+
using System.Linq;
13+
using NHibernate.Cfg.MappingSchema;
14+
using NHibernate.Mapping.ByCode;
15+
using NUnit.Framework;
16+
using NHibernate.Linq;
17+
18+
namespace NHibernate.Test.NHSpecificTest.GH3218
19+
{
20+
using System.Threading.Tasks;
21+
[TestFixture]
22+
public class ContainsParameterFixtureAsync : TestCaseMappingByCode
23+
{
24+
protected override HbmMapping GetMappings()
25+
{
26+
var mapper = new ModelMapper();
27+
mapper.Class<Child>(rc =>
28+
{
29+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
30+
rc.Property(x => x.Name);
31+
rc.Component(
32+
x => x.Component,
33+
ekm =>
34+
{
35+
ekm.Property(ek => ek.Id1);
36+
ekm.Property(ek => ek.Id2);
37+
});
38+
});
39+
mapper.Class<Entity>(rc =>
40+
{
41+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
42+
rc.Property(x => x.Name);
43+
rc.Bag(x => x.List, m => { }, r => r.OneToMany());
44+
});
45+
46+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
47+
}
48+
49+
[Test]
50+
public async Task ContainsOnIdAsync()
51+
{
52+
using (var session = OpenSession())
53+
{
54+
Guid clientId = Guid.NewGuid();
55+
await (session.Query<Entity>().Where(x => x.List.Select(l => l.Id).Contains(clientId)).ToListAsync());
56+
}
57+
}
58+
59+
[Test]
60+
public async Task ContainsOnNameWithInnerSubqueryAsync()
61+
{
62+
using (var session = OpenSession())
63+
{
64+
var clientId = "aa";
65+
await (session.Query<Entity>().Where(x =>
66+
x.List.Where(l => session.Query<Entity>().Any(s => s.Name == l.Name)).Select(l => l.Name)
67+
.Contains(clientId)).ToListAsync());
68+
}
69+
}
70+
71+
[Test]
72+
public async Task ContainsOnEntityAsync()
73+
{
74+
using (var session = OpenSession())
75+
{
76+
var client = await (session.LoadAsync<Child>(Guid.NewGuid()));
77+
await (session.Query<Entity>().Where(x => x.List.Contains(client)).ToListAsync());
78+
}
79+
}
80+
81+
[Test]
82+
public async Task ContainsOnNameAsync()
83+
{
84+
using (var session = OpenSession())
85+
{
86+
var client = "aaa";
87+
await (session.Query<Entity>().Where(x => x.List.Select(l => l.Name).Contains(client)).ToListAsync());
88+
}
89+
}
90+
91+
[Test]
92+
public async Task ContainsOnComponentAsync()
93+
{
94+
using (var session = OpenSession())
95+
{
96+
var client = new CompositeKey() { Id1 = 1, Id2 = 2 };
97+
await (session.Query<Entity>().Where(x => x.List.Select(l => l.Component).Contains(client)).ToListAsync());
98+
}
99+
}
100+
}
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Linq;
3+
using NHibernate.Cfg.MappingSchema;
4+
using NHibernate.Mapping.ByCode;
5+
using NUnit.Framework;
6+
7+
namespace NHibernate.Test.NHSpecificTest.GH3218
8+
{
9+
[TestFixture]
10+
public class ContainsParameterFixture : TestCaseMappingByCode
11+
{
12+
protected override HbmMapping GetMappings()
13+
{
14+
var mapper = new ModelMapper();
15+
mapper.Class<Child>(rc =>
16+
{
17+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
18+
rc.Property(x => x.Name);
19+
rc.Component(
20+
x => x.Component,
21+
ekm =>
22+
{
23+
ekm.Property(ek => ek.Id1);
24+
ekm.Property(ek => ek.Id2);
25+
});
26+
});
27+
mapper.Class<Entity>(rc =>
28+
{
29+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
30+
rc.Property(x => x.Name);
31+
rc.Bag(x => x.List, m => { }, r => r.OneToMany());
32+
});
33+
34+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
35+
}
36+
37+
[Test]
38+
public void ContainsOnId()
39+
{
40+
using (var session = OpenSession())
41+
{
42+
Guid clientId = Guid.NewGuid();
43+
session.Query<Entity>().Where(x => x.List.Select(l => l.Id).Contains(clientId)).ToList();
44+
}
45+
}
46+
47+
[Test]
48+
public void ContainsOnNameWithInnerSubquery()
49+
{
50+
using (var session = OpenSession())
51+
{
52+
var clientId = "aa";
53+
session.Query<Entity>().Where(x =>
54+
x.List.Where(l => session.Query<Entity>().Any(s => s.Name == l.Name)).Select(l => l.Name)
55+
.Contains(clientId)).ToList();
56+
}
57+
}
58+
59+
[Test]
60+
public void ContainsOnEntity()
61+
{
62+
using (var session = OpenSession())
63+
{
64+
var client = session.Load<Child>(Guid.NewGuid());
65+
session.Query<Entity>().Where(x => x.List.Contains(client)).ToList();
66+
}
67+
}
68+
69+
[Test]
70+
public void ContainsOnName()
71+
{
72+
using (var session = OpenSession())
73+
{
74+
var client = "aaa";
75+
session.Query<Entity>().Where(x => x.List.Select(l => l.Name).Contains(client)).ToList();
76+
}
77+
}
78+
79+
[Test]
80+
public void ContainsOnComponent()
81+
{
82+
using (var session = OpenSession())
83+
{
84+
var client = new CompositeKey() { Id1 = 1, Id2 = 2 };
85+
session.Query<Entity>().Where(x => x.List.Select(l => l.Component).Contains(client)).ToList();
86+
}
87+
}
88+
}
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace NHibernate.Test.NHSpecificTest.GH3218
5+
{
6+
public class Entity
7+
{
8+
public virtual Guid Id { get; set; }
9+
public virtual string Name { get; set; }
10+
public virtual IList<Child> List { get; set; }
11+
}
12+
13+
public class Child
14+
{
15+
public virtual Guid Id { get; set; }
16+
public virtual string Name { get; set; }
17+
public virtual CompositeKey Component { get; set; }
18+
}
19+
20+
public class CompositeKey
21+
{
22+
public int Id1 { get; set; }
23+
public int Id2 { get; set; }
24+
25+
public override bool Equals(object obj)
26+
{
27+
var key = obj as CompositeKey;
28+
return key != null
29+
&& Id1 == key.Id1
30+
&& Id2 == key.Id2;
31+
}
32+
33+
public override int GetHashCode()
34+
{
35+
var hashCode = -1596524975;
36+
hashCode = hashCode * -1521134295 + Id1.GetHashCode();
37+
hashCode = hashCode * -1521134295 + Id2.GetHashCode();
38+
return hashCode;
39+
}
40+
}
41+
}

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

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
using System;
2-
using System.Collections;
3-
using System.Collections.Generic;
1+
using System.Collections;
42
using System.Linq;
5-
using System.Linq.Expressions;
63
using NHibernate.Hql.Ast;
4+
using NHibernate.Hql.Ast.ANTLR;
75
using Remotion.Linq.Clauses.ResultOperators;
86

97
namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
@@ -38,7 +36,7 @@ public void Process(ContainsResultOperator resultOperator, QueryModelVisitor que
3836
if (itemExpression is HqlParameter)
3937
{
4038
tree.AddWhereClause(tree.TreeBuilder.Equality(
41-
tree.TreeBuilder.Ident(GetFromAlias(tree.Root).AstNode.Text),
39+
GetSelectExpression(tree.Root),
4240
itemExpression));
4341
ProcessAny.Process(tree);
4442
}
@@ -54,9 +52,9 @@ private static HqlRange GetFromRangeClause(HqlTreeNode node)
5452
return node.NodesPreOrder.OfType<HqlRange>().First();
5553
}
5654

57-
private static HqlAlias GetFromAlias(HqlTreeNode node)
55+
private static HqlExpression GetSelectExpression(HqlTreeNode node)
5856
{
59-
return node.NodesPreOrder.Single(n => n is HqlRange).Children.Single(n => n is HqlAlias) as HqlAlias;
57+
return node.NodesPreOrder.First(x => x.AstNode.Type == HqlSqlWalker.SELECT).Children.Single() as HqlExpression;
6058
}
6159

6260
private static bool IsEmptyList(HqlParameter source, VisitorParameters parameters)

0 commit comments

Comments
 (0)