Skip to content

Commit a6c4a5a

Browse files
Fix IFilter.SetParameterList not supporting HashSet<T> arguments.
Fixes #1585 Co-authored-by: Alexander Zaytsev <[email protected]>
1 parent 0d1a4b7 commit a6c4a5a

File tree

8 files changed

+112
-21
lines changed

8 files changed

+112
-21
lines changed

src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,35 @@ public async Task InStyleFilterParameterAsync()
366366
}
367367
}
368368

369+
[Test]
370+
public void InStyleFilterParameterWithHashSetAsync()
371+
{
372+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
373+
// one-to-many loading tests
374+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
375+
log.Info("Starting one-to-many collection loader filter tests with HashSet.");
376+
using (var session = OpenSession())
377+
{
378+
Assert.Multiple(
379+
async () =>
380+
{
381+
session.EnableFilter("regionlist")
382+
.SetParameterList("regions", new HashSet<string> { "LA", "APAC" });
383+
384+
log.Debug("Performing query of Salespersons");
385+
var salespersons = await (session.CreateQuery("from Salesperson").ListAsync());
386+
Assert.That(salespersons.Count, Is.EqualTo(1), "Incorrect salesperson count");
387+
388+
session.EnableFilter("guidlist")
389+
.SetParameterList("guids", new HashSet<Guid> { testData.Product1Guid, testData.Product2Guid });
390+
391+
log.Debug("Performing query of Products");
392+
var products = await (session.CreateQuery("from Product").ListAsync());
393+
Assert.That(products.Count, Is.EqualTo(2), "Incorrect product count");
394+
});
395+
}
396+
}
397+
369398
[Test]
370399
public async Task ManyToManyFilterOnCriteriaAsync()
371400
{
@@ -572,6 +601,8 @@ private class TestData
572601
public DateTime nextMonth;
573602
public DateTime sixMonthsAgo;
574603
public DateTime fourMonthsAgo;
604+
public Guid Product1Guid;
605+
public Guid Product2Guid;
575606

576607
private DynamicFilterTestAsync outer;
577608

@@ -631,6 +662,8 @@ public TestData(DynamicFilterTestAsync outer)
631662
product1.StockNumber = (123);
632663
product1.EffectiveStartDate = (lastMonth);
633664
product1.EffectiveEndDate = (nextMonth);
665+
product1.ProductGuid = Guid.NewGuid();
666+
Product1Guid = product1.ProductGuid;
634667

635668
product1.AddCategory(cat1);
636669
product1.AddCategory(cat2);
@@ -655,6 +688,8 @@ public TestData(DynamicFilterTestAsync outer)
655688
product2.StockNumber = (124);
656689
product2.EffectiveStartDate = (sixMonthsAgo);
657690
product2.EffectiveEndDate = (DateTime.Today);
691+
product2.ProductGuid = Guid.NewGuid();
692+
Product2Guid = product2.ProductGuid;
658693

659694
Category cat3 = new Category("test cat 2", sixMonthsAgo, DateTime.Today);
660695
product2.AddCategory(cat3);
@@ -731,6 +766,8 @@ public void Prepare()
731766
product1.StockNumber = (123);
732767
product1.EffectiveStartDate = (lastMonth);
733768
product1.EffectiveEndDate = (nextMonth);
769+
product1.ProductGuid = Guid.NewGuid();
770+
Product1Guid = product1.ProductGuid;
734771

735772
product1.AddCategory(cat1);
736773
product1.AddCategory(cat2);
@@ -755,6 +792,8 @@ public void Prepare()
755792
product2.StockNumber = (124);
756793
product2.EffectiveStartDate = (sixMonthsAgo);
757794
product2.EffectiveEndDate = (DateTime.Today);
795+
product2.ProductGuid = Guid.NewGuid();
796+
Product2Guid = product2.ProductGuid;
758797

759798
Category cat3 = new Category("test cat 2", sixMonthsAgo, DateTime.Today);
760799
product2.AddCategory(cat3);

src/NHibernate.Test/FilterTest/DynamicFilterTest.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,35 @@ public void InStyleFilterParameter()
354354
}
355355
}
356356

357+
[Test]
358+
public void InStyleFilterParameterWithHashSet()
359+
{
360+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
361+
// one-to-many loading tests
362+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
363+
log.Info("Starting one-to-many collection loader filter tests with HashSet.");
364+
using (var session = OpenSession())
365+
{
366+
Assert.Multiple(
367+
() =>
368+
{
369+
session.EnableFilter("regionlist")
370+
.SetParameterList("regions", new HashSet<string> { "LA", "APAC" });
371+
372+
log.Debug("Performing query of Salespersons");
373+
var salespersons = session.CreateQuery("from Salesperson").List();
374+
Assert.That(salespersons.Count, Is.EqualTo(1), "Incorrect salesperson count");
375+
376+
session.EnableFilter("guidlist")
377+
.SetParameterList("guids", new HashSet<Guid> { testData.Product1Guid, testData.Product2Guid });
378+
379+
log.Debug("Performing query of Products");
380+
var products = session.CreateQuery("from Product").List();
381+
Assert.That(products.Count, Is.EqualTo(2), "Incorrect product count");
382+
});
383+
}
384+
}
385+
357386
[Test]
358387
public void ManyToManyFilterOnCriteria()
359388
{
@@ -560,6 +589,8 @@ private class TestData
560589
public DateTime nextMonth;
561590
public DateTime sixMonthsAgo;
562591
public DateTime fourMonthsAgo;
592+
public Guid Product1Guid;
593+
public Guid Product2Guid;
563594

564595
private DynamicFilterTest outer;
565596

@@ -619,6 +650,8 @@ public void Prepare()
619650
product1.StockNumber = (123);
620651
product1.EffectiveStartDate = (lastMonth);
621652
product1.EffectiveEndDate = (nextMonth);
653+
product1.ProductGuid = Guid.NewGuid();
654+
Product1Guid = product1.ProductGuid;
622655

623656
product1.AddCategory(cat1);
624657
product1.AddCategory(cat2);
@@ -643,6 +676,8 @@ public void Prepare()
643676
product2.StockNumber = (124);
644677
product2.EffectiveStartDate = (sixMonthsAgo);
645678
product2.EffectiveEndDate = (DateTime.Today);
679+
product2.ProductGuid = Guid.NewGuid();
680+
Product2Guid = product2.ProductGuid;
646681

647682
Category cat3 = new Category("test cat 2", sixMonthsAgo, DateTime.Today);
648683
product2.AddCategory(cat3);

src/NHibernate.Test/FilterTest/Product.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public virtual ISet<Category> Categories
7575
set { categories = value; }
7676
}
7777

78+
public virtual Guid ProductGuid { get; set; }
79+
7880
public override int GetHashCode()
7981
{
8082
return stockNumber;

src/NHibernate.Test/FilterTest/classes.hbm.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
<property name="EffectiveStartDate" column="eff_start_dt" type="Date"/>
8080
<property name="EffectiveEndDate" column="eff_end_dt" type="Date"/>
8181

82+
<property name="ProductGuid"/>
83+
8284
<set cascade="none" inverse="true" name="OrderLineItems">
8385
<key column="PROD_ID"/>
8486
<one-to-many class="LineItem"/>
@@ -93,6 +95,7 @@
9395
</set>
9496

9597
<filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
98+
<filter name="guidlist" condition="ProductGuid IN (:guids)"/>
9699
</class>
97100

98101
<class name="Salesperson" table="SALES_PERSON">
@@ -118,4 +121,4 @@
118121
<filter name="regionlist" condition="REG IN (:regions)"/>
119122
</class>
120123

121-
</hibernate-mapping>
124+
</hibernate-mapping>

src/NHibernate.Test/FilterTest/defs.hbm.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@
2424
<filter-def name="cat">
2525
<filter-param name="catId" type="long"/>
2626
</filter-def>
27-
</hibernate-mapping>
27+
28+
<filter-def name="guidlist">
29+
<filter-param name="guids" type="guid"/>
30+
</filter-def>
31+
</hibernate-mapping>

src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,16 @@ private SqlString ExpandDynamicFilterParameters(SqlString sqlString, ICollection
151151
string parameterName = parts[1];
152152
var filter = (FilterImpl)enabledFilters[filterName];
153153

154-
object value = filter.GetParameter(parameterName);
154+
var collectionSpan = filter.GetParameterSpan(parameterName);
155155
IType type = filter.FilterDefinition.GetParameterType(parameterName);
156156
int parameterColumnSpan = type.GetColumnSpan(session.Factory);
157-
var collectionValue = value as ICollection;
158-
int? collectionSpan = null;
159157

160158
// Add query chunk
161-
string typeBindFragment = string.Join(", ", Enumerable.Repeat("?", parameterColumnSpan).ToArray());
159+
string typeBindFragment = string.Join(", ", Enumerable.Repeat("?", parameterColumnSpan));
162160
string bindFragment;
163-
if (collectionValue != null && !type.ReturnedClass.IsArray)
161+
if (collectionSpan.HasValue && !type.ReturnedClass.IsArray)
164162
{
165-
collectionSpan = collectionValue.Count;
166-
bindFragment = string.Join(", ", Enumerable.Repeat(typeBindFragment, collectionValue.Count).ToArray());
163+
bindFragment = string.Join(", ", Enumerable.Repeat(typeBindFragment, collectionSpan.Value));
167164
}
168165
else
169166
{

src/NHibernate/Impl/FilterImpl.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class FilterImpl : IFilter
1616
private FilterDefinition definition;
1717

1818
private readonly IDictionary<string, object> parameters = new Dictionary<string, object>();
19+
private readonly Dictionary<string, int> _parameterSpans = new Dictionary<string, int>();
1920

2021
public void AfterDeserialize(FilterDefinition factoryDefinition)
2122
{
@@ -75,20 +76,21 @@ public IFilter SetParameter(string name, object value)
7576
/// <param name="name">The parameter's name.</param>
7677
/// <param name="values">The values to be expanded into an SQL IN list.</param>
7778
/// <returns>This FilterImpl instance (for method chaining).</returns>
79+
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="values"/> are <see langword="null" />.</exception>
7880
public IFilter SetParameterList<T>(string name, ICollection<T> values)
7981
{
82+
if (values == null)
83+
throw new ArgumentNullException(nameof(values), "Collection must be not null!");
84+
8085
var type = definition.GetParameterType(name);
8186
if (type == null)
82-
{
8387
throw new HibernateException("Undefined filter parameter [" + name + "]");
84-
}
8588

8689
if (!type.ReturnedClass.IsAssignableFrom(typeof(T)))
87-
{
8890
throw new HibernateException("Incorrect type for parameter [" + name + "]");
89-
}
9091

91-
parameters[name] = values ?? throw new ArgumentException("Collection must be not null!", nameof(values));
92+
_parameterSpans[name] = values.Count;
93+
parameters[name] = values;
9294
return this;
9395
}
9496

@@ -99,6 +101,18 @@ public object GetParameter(string name)
99101
return result;
100102
}
101103

104+
/// <summary>
105+
/// Get the span of a value list parameter by name. <see langword="null" /> if the parameter is not a value list
106+
/// or if there is no such parameter.
107+
/// </summary>
108+
/// <param name="name">The parameter name.</param>
109+
/// <returns>The parameter span, or <see langword="null" /> if the parameter is not a value list or
110+
/// if there is no such parameter.</returns>
111+
public int? GetParameterSpan(string name)
112+
{
113+
return _parameterSpans.TryGetValue(name, out var result) ? result : default(int?);
114+
}
115+
102116
/// <summary>
103117
/// Perform validation of the filter state. This is used to verify the
104118
/// state of the filter after its enablement and before its use.

src/NHibernate/Loader/Loader.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,19 +1859,16 @@ protected SqlString ExpandDynamicFilterParameters(SqlString sqlString, ICollecti
18591859
string parameterName = parts[1];
18601860
var filter = (FilterImpl)enabledFilters[filterName];
18611861

1862-
object value = filter.GetParameter(parameterName);
1862+
int? collectionSpan = filter.GetParameterSpan(parameterName);
18631863
IType type = filter.FilterDefinition.GetParameterType(parameterName);
18641864
int parameterColumnSpan = type.GetColumnSpan(session.Factory);
1865-
var collectionValue = value as ICollection;
1866-
int? collectionSpan = null;
18671865

18681866
// Add query chunk
1869-
string typeBindFragment = string.Join(", ", Enumerable.Repeat("?", parameterColumnSpan).ToArray());
1867+
string typeBindFragment = string.Join(", ", Enumerable.Repeat("?", parameterColumnSpan));
18701868
string bindFragment;
1871-
if (collectionValue != null && !type.ReturnedClass.IsArray)
1869+
if (collectionSpan.HasValue && !type.ReturnedClass.IsArray)
18721870
{
1873-
collectionSpan = collectionValue.Count;
1874-
bindFragment = string.Join(", ", Enumerable.Repeat(typeBindFragment, collectionValue.Count).ToArray());
1871+
bindFragment = string.Join(", ", Enumerable.Repeat(typeBindFragment, collectionSpan.Value));
18751872
}
18761873
else
18771874
{

0 commit comments

Comments
 (0)