Skip to content

Commit cd1c446

Browse files
authored
Merge pull request #136 from nhibernate/feature/spatial-restriction-criteria
Implement missing spatial restriction criteria
2 parents 5c8a953 + 5a92850 commit cd1c446

40 files changed

+9156
-2927
lines changed

NHibernate.Spatial.MsSql/Dialect/MsSql2012FunctionRegistration.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,9 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
413413
case SpatialRelation.CoveredBy:
414414
return GetSpatialRelationString(anotherGeometry, SpatialRelation.Covers, geometry, criterion);
415415

416+
case SpatialRelation.EqualsExact:
417+
throw new NotSupportedException($"{relation} not supported by SQL Server");
418+
416419
default:
417420
// NOTE: Cast is only required if "geometry" is passed in as a parameter
418421
// directly, rather than as a column name. This is because parameter
@@ -434,6 +437,29 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
434437
}
435438
}
436439

440+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
441+
{
442+
switch (relation)
443+
{
444+
case SpatialRelation.IsWithinDistance:
445+
return new SqlStringBuilder()
446+
.Add("CASE WHEN ")
447+
.AddObject(geometry)
448+
.Add(".STDistance(")
449+
.AddObject(anotherGeometry)
450+
.Add(")")
451+
.Add(" <= ")
452+
.Add(parameter.ToString())
453+
.Add(" THEN 1 ELSE 0 END")
454+
.Add(criterion ? " = 1" : "")
455+
.ToSqlString();
456+
case SpatialRelation.Relate:
457+
return GetSpatialRelateString(geometry, anotherGeometry, parameter, true, criterion);
458+
default:
459+
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
460+
}
461+
}
462+
437463
public SqlString GetSpatialFilterString(string tableAlias, string geometryColumnName, string primaryKeyColumnName, string tableName, Parameter parameter)
438464
{
439465
return new SqlStringBuilder(6)

NHibernate.Spatial.MsSql/Dialect/MsSql2012SpatialDialect.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
7676
return worker.GetSpatialRelationString(geometry, relation, anotherGeometry, criterion);
7777
}
7878

79+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
80+
{
81+
return worker.GetSpatialRelationString(geometry, relation, anotherGeometry, parameter, criterion);
82+
}
83+
7984
public SqlString GetSpatialFilterString(string tableAlias, string geometryColumnName, string primaryKeyColumnName, string tableName, Parameter parameter)
8085
{
8186
return worker.GetSpatialFilterString(tableAlias, geometryColumnName, primaryKeyColumnName, tableName, parameter);

NHibernate.Spatial.MySQL/Dialect/MySQL57SpatialDialect.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,9 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
331331
case SpatialRelation.CoveredBy:
332332
return GetSpatialRelationString(anotherGeometry, SpatialRelation.Covers, geometry, criterion);
333333

334+
case SpatialRelation.EqualsExact:
335+
throw new NotSupportedException($"{relation} not supported by SQL Server");
336+
334337
default:
335338
return new SqlStringBuilder(6)
336339
.Add(SpatialDialect.IsoPrefix)
@@ -344,6 +347,26 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
344347
}
345348
}
346349

350+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
351+
{
352+
switch (relation)
353+
{
354+
case SpatialRelation.IsWithinDistance:
355+
return new SqlStringBuilder()
356+
.Add(SpatialDialect.IsoPrefix)
357+
.Add("Distance(")
358+
.AddObject(geometry)
359+
.Add(", ")
360+
.AddObject(anotherGeometry)
361+
.Add(")")
362+
.Add(" <= ")
363+
.Add(parameter.ToString())
364+
.ToSqlString();
365+
default:
366+
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
367+
}
368+
}
369+
347370
public SqlString GetSpatialRelateString(object geometry, object anotherGeometry, object pattern, bool isStringPattern, bool criterion)
348371
{
349372
var builder = new SqlStringBuilder();

NHibernate.Spatial.PostGis/Dialect/PostGis20Dialect.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,16 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
320320
case SpatialRelation.CoveredBy:
321321
return GetSpatialRelationString(anotherGeometry, SpatialRelation.Covers, geometry, criterion);
322322

323+
case SpatialRelation.EqualsExact:
324+
return new SqlStringBuilder()
325+
.Add(SpatialDialect.IsoPrefix)
326+
.Add("OrderingEquals(")
327+
.AddObject(geometry)
328+
.Add(", ")
329+
.AddObject(anotherGeometry)
330+
.Add(")")
331+
.ToSqlString();
332+
323333
default:
324334
return new SqlStringBuilder(6)
325335
.Add(SpatialDialect.IsoPrefix)
@@ -335,6 +345,39 @@ public SqlString GetSpatialRelationString(object geometry, SpatialRelation relat
335345
}
336346
}
337347

348+
public SqlString GetSpatialRelationString(object geometry, SpatialRelation relation, object anotherGeometry, object parameter, bool criterion)
349+
{
350+
switch (relation)
351+
{
352+
case SpatialRelation.IsWithinDistance:
353+
return new SqlStringBuilder()
354+
.Add(SpatialDialect.IsoPrefix)
355+
.Add("DWithin")
356+
.Add("(")
357+
.AddObject(geometry)
358+
.Add(", ")
359+
.AddObject(anotherGeometry)
360+
.Add(", ")
361+
.Add(parameter.ToString())
362+
.Add(")")
363+
.ToSqlString();
364+
case SpatialRelation.Relate:
365+
return new SqlStringBuilder()
366+
.Add(SpatialDialect.IsoPrefix)
367+
.Add(relation.ToString())
368+
.Add("(")
369+
.AddObject(geometry)
370+
.Add(", ")
371+
.AddObject(anotherGeometry)
372+
.Add(", '")
373+
.Add(parameter.ToString())
374+
.Add("')")
375+
.ToSqlString();
376+
default:
377+
throw new ArgumentOutOfRangeException(nameof(relation), relation, "Unsupported spatial relation");
378+
}
379+
}
380+
338381
public SqlString GetSpatialRelateString(object geometry, object anotherGeometry, object pattern, bool isStringPattern, bool criterion)
339382
{
340383
var builder = new SqlStringBuilder();

NHibernate.Spatial/Criterion/Lambda/LambdaSpatialRestrictionBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ public AbstractCriterion Eq(object value)
107107
/// <summary>
108108
/// Apply a "eq exact" constraint to the named property
109109
/// </summary>
110-
public AbstractCriterion EqExact(object value, double tolerance)
110+
public AbstractCriterion EqExact(object value)
111111
{
112-
return Process(SpatialRestrictions.EqExact(propertyName, value, tolerance));
112+
return Process(SpatialRestrictions.EqExact(propertyName, value));
113113
}
114114

115115
/// <summary>

NHibernate.Spatial/Criterion/Lambda/QueryOverSpatialRestrictionBuilderBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ public TReturn Eq(object value)
101101
/// <summary>
102102
/// Apply a "eq exact" constraint to the named property
103103
/// </summary>
104-
public TReturn EqExact(object value, double tolerance)
104+
public TReturn EqExact(object value)
105105
{
106-
return Add(SpatialRestrictions.EqExact(propertyName, value, tolerance));
106+
return Add(SpatialRestrictions.EqExact(propertyName, value));
107107
}
108108

109109
/// <summary>

NHibernate.Spatial/Criterion/SpatialProjections.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,17 @@ public static SpatialProjection Equals(string propertyName, string anotherProper
246246
return new SpatialRelationProjection(propertyName, SpatialRelation.Equals, anotherPropertyName);
247247
}
248248

249+
/// <summary>
250+
/// Determines whether the specified geometry property is exactly equal to another geometry property.
251+
/// </summary>
252+
/// <param name="propertyName">Name of the property.</param>
253+
/// <param name="anotherPropertyName">Name of another property.</param>
254+
/// <returns></returns>
255+
public static SpatialProjection EqualsExact(string propertyName, string anotherPropertyName)
256+
{
257+
return new SpatialRelationProjection(propertyName, SpatialRelation.EqualsExact, anotherPropertyName);
258+
}
259+
249260
/// <summary>
250261
/// Determines whether the specified geometry property intersects another geometry property.
251262
/// </summary>
@@ -257,6 +268,18 @@ public static SpatialProjection Intersects(string propertyName, string anotherPr
257268
return new SpatialRelationProjection(propertyName, SpatialRelation.Intersects, anotherPropertyName);
258269
}
259270

271+
/// <summary>
272+
/// Determines whether the specified geometry property is within a given distance of another geometry.
273+
/// </summary>
274+
/// <param name="propertyName">Name of the property.</param>
275+
/// <param name="anotherPropertyName">Name of another property.</param>
276+
/// <param name="distance">The distance.</param>
277+
/// <returns></returns>
278+
public static SpatialProjection IsWithinDistance(string propertyName, string anotherPropertyName, double distance)
279+
{
280+
return new SpatialRelationProjection(propertyName, SpatialRelation.IsWithinDistance, anotherPropertyName, distance);
281+
}
282+
260283
/// <summary>
261284
/// Determines whether the specified geometry property overlaps another geometry property.
262285
/// </summary>

NHibernate.Spatial/Criterion/SpatialProjectionsLambda.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,17 @@ public static SpatialProjection Equals<T>(Expression<Func<T, object>> expression
258258
return Equals(GetPropertyName(expression), GetPropertyName(anotherExpression));
259259
}
260260

261+
/// <summary>
262+
/// Determines whether the specified geometry property is exactly equal to another geometry property.
263+
/// </summary>
264+
/// <param name="expression">Name of the property.</param>
265+
/// <param name="anotherExpression">Name of another property.</param>
266+
/// <returns></returns>
267+
public static SpatialProjection EqualsExact<T>(Expression<Func<T, object>> expression, Expression<Func<T, object>> anotherExpression)
268+
{
269+
return EqualsExact(GetPropertyName(expression), GetPropertyName(anotherExpression));
270+
}
271+
261272
/// <summary>
262273
/// Determines whether the specified geometry property intersects another geometry property.
263274
/// </summary>
@@ -269,6 +280,18 @@ public static SpatialProjection Intersects<T>(Expression<Func<T, object>> expres
269280
return Intersects(GetPropertyName(expression), GetPropertyName(anotherExpression));
270281
}
271282

283+
/// <summary>
284+
/// Determines whether the specified geometry property is within a given distance of another geometry.
285+
/// </summary>
286+
/// <param name="expression">Name of the property.</param>
287+
/// <param name="anotherExpression">Name of another property.</param>
288+
/// <param name="distance">The distance.</param>
289+
/// <returns></returns>
290+
public static SpatialProjection IsWithinDistance<T>(Expression<Func<T, object>> expression, Expression<Func<T, object>> anotherExpression, double distance)
291+
{
292+
return IsWithinDistance(GetPropertyName(expression), GetPropertyName(anotherExpression), distance);
293+
}
294+
272295
/// <summary>
273296
/// Determines whether the specified geometry property overlaps another geometry property.
274297
/// </summary>

NHibernate.Spatial/Criterion/SpatialRelationCriterion.cs

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,23 @@ namespace NHibernate.Spatial.Criterion
3232
[Serializable]
3333
public class SpatialRelationCriterion : AbstractCriterion
3434
{
35-
private readonly string propertyName;
36-
private readonly SpatialRelation relation;
37-
private readonly object anotherGeometry;
35+
private readonly string _propertyName;
36+
private readonly SpatialRelation _relation;
37+
private readonly object _anotherGeometry;
38+
private readonly object _parameter;
39+
40+
/// <summary>
41+
/// Initializes a new instance of the <see cref="SpatialRelationCriterion"/> class.
42+
/// </summary>
43+
/// <param name="propertyName">Name of the property.</param>
44+
/// <param name="relation">The relation.</param>
45+
/// <param name="anotherGeometry">Another geometry.</param>
46+
/// <param name="parameter">Additional parameter value</param>
47+
public SpatialRelationCriterion(string propertyName, SpatialRelation relation, object anotherGeometry, object parameter)
48+
: this(propertyName, relation, anotherGeometry)
49+
{
50+
_parameter = parameter;
51+
}
3852

3953
/// <summary>
4054
/// Initializes a new instance of the <see cref="SpatialRelationCriterion"/> class.
@@ -44,9 +58,9 @@ public class SpatialRelationCriterion : AbstractCriterion
4458
/// <param name="anotherGeometry">Another geometry.</param>
4559
public SpatialRelationCriterion(string propertyName, SpatialRelation relation, object anotherGeometry)
4660
{
47-
this.propertyName = propertyName;
48-
this.relation = relation;
49-
this.anotherGeometry = anotherGeometry;
61+
_propertyName = propertyName;
62+
_relation = relation;
63+
_anotherGeometry = anotherGeometry;
5064
}
5165

5266
/// <summary>
@@ -59,9 +73,9 @@ public SpatialRelationCriterion(string propertyName, SpatialRelation relation, o
5973
/// </returns>
6074
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
6175
{
62-
if (anotherGeometry is Geometry)
76+
if (_anotherGeometry is Geometry)
6377
{
64-
return new[] { criteriaQuery.GetTypedValue(criteria, propertyName, anotherGeometry) };
78+
return new[] { criteriaQuery.GetTypedValue(criteria, _propertyName, _anotherGeometry) };
6579
}
6680
return Array.Empty<TypedValue>();
6781
}
@@ -81,9 +95,8 @@ public override IProjection[] GetProjections()
8195
/// </returns>
8296
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
8397
{
84-
//criteriaQuery.AddUsedTypedValues(GetTypedValues(criteria, criteriaQuery));
8598
var spatialDialect = (ISpatialDialect) criteriaQuery.Factory.Dialect;
86-
string[] columns1 = GetColumnNames(criteria, criteriaQuery, propertyName);
99+
string[] columns1 = GetColumnNames(criteria, criteriaQuery, _propertyName);
87100

88101
var builder = new SqlStringBuilder(10*columns1.Length);
89102
for (int i = 0; i < columns1.Length; i++)
@@ -92,17 +105,25 @@ public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteri
92105
{
93106
builder.Add(" AND ");
94107
}
95-
if (anotherGeometry is Geometry)
108+
109+
object anotherGeometry;
110+
if (_anotherGeometry is Geometry)
96111
{
97112
var parameters = criteriaQuery.NewQueryParameter(GetTypedValues(criteria, criteriaQuery)[0]).ToArray();
98-
builder.Add(spatialDialect.GetSpatialRelationString(columns1[i], relation, parameters.Single(), true));
113+
anotherGeometry = parameters.Single();
99114
}
100115
else
101116
{
102-
string[] columns2 = GetColumnNames(criteria, criteriaQuery, (string) anotherGeometry);
103-
builder.Add(spatialDialect.GetSpatialRelationString(columns1[i], relation, columns2[i], true));
117+
string[] columns2 = GetColumnNames(criteria, criteriaQuery, (string) _anotherGeometry);
118+
anotherGeometry = columns2[i];
104119
}
120+
121+
var spatialRelationString = _parameter == null
122+
? spatialDialect.GetSpatialRelationString(columns1[i], _relation, anotherGeometry, true)
123+
: spatialDialect.GetSpatialRelationString(columns1[i], _relation, anotherGeometry, _parameter, true);
124+
builder.Add(spatialRelationString);
105125
}
126+
106127
return builder.ToSqlString();
107128
}
108129

@@ -119,11 +140,11 @@ public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteri
119140
public override string ToString()
120141
{
121142
return new StringBuilder()
122-
.Append(relation)
143+
.Append(_relation)
123144
.Append("(")
124-
.Append(propertyName)
145+
.Append(_propertyName)
125146
.Append(", ")
126-
.Append(anotherGeometry is Geometry ? "<Geometry>" : anotherGeometry.ToString())
147+
.Append(_anotherGeometry is Geometry ? "<Geometry>" : _anotherGeometry.ToString())
127148
.Append(")")
128149
.ToString();
129150
}

0 commit comments

Comments
 (0)