2009-12-02 62 views
1

我有一个存储库中的现有高级搜索方法,检查FormCollection是否存在搜索条件,如果存在,则向搜索添加条件。使用NHibernate和SQL Server地理高级搜索距离

public IList<Residence> GetForAdvancedSearch(FormCollection collection) 
{ 
    var criteria = Session.CreateCriteria(typeof(Residence)) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

    if (collection["MinBedrooms"] != null) 
    { 
    criteria 
     .Add(Restrictions.Ge("Bedrooms", int.Parse(collection["MinBedrooms"]))); 
    } 

    // ... many criteria omitted for brevity 

    return criteria.List<Residence>(); 
} 

我也有一个基本的距离搜索,以找到每个住所离搜索标准有多远。用于查询的HBM是

<sql-query name="Residence.Nearest"> 
    <return alias="residence" class="Residences.Domain.Residence, Residences"/> 
    <return-scalar column="Distance" type="float"/> 
    SELECT R.*, dbo.GetDistance(:point, R.Coordinate) AS Distance 
    FROM Residence R 
    WHERE Distance < 10 
    ORDER BY Distance 
</sql-query> 

我必须定义一个函数来计算距离,因为没有办法让NHibernate的逃避地理功能冒号:

CREATE FUNCTION dbo.GetDistance 
(
    @firstPoint nvarchar(100), 
    @secondPoint GEOMETRY 
) 
RETURNS float 
AS 
BEGIN 
    RETURN GEOGRAPHY::STGeomFromText(
    @firstPoint, 4326).STDistance(@secondPoint.STAsText())/1609.344 
END 

而存储库调用这个命名查询:

return Session 
    .GetNamedQuery("Residence.Nearest") 
    .SetString("point", String.Format("POINT({0} {1})", latitude, longitude)) 
    .List(); 

所以我的问题是;我如何将两者结合起来(或从头开始),因此我可以将高级搜索结果过滤为仅包含搜索位置10英里内的住宅?

UPDATE我一直在使用NHibernate.Spatial用下面的代码尝试:

criteria.Add(SpatialExpression.IsWithinDistance(
    "Coordinate", new Coordinate(latitude, longitude), 10)); 

SpatialExpression.IsWithinDistance返回System.NotImplementedException

回答

0

创建的投影的是,实际上,增加了一个新的距离列的结果,这是由称为UDF计算,然后添加限制给它:

var query = String.Format(
    "dbo.GetDistance('POINT({0} {1}', Coordinate) AS Distance", 
    latitude, longitude); 
criteria 
    .Add(Restrictions.Le(Projections.SqlProjection(
     query, 
     new [] {"Distance"}, 
     new [] {NHibernateUtil.Double}), 10)); 

UPDATE

nb虽然这一定是在我发布它时发挥作用的,但它不再起作用。 NHibernate不喜欢'。'后dbo,并说

“无法解决属性:dbo:Residences.Domain.Residence”。

如果我删除'dbo'。我得到

“'GetDistance'不是公认的内置函数名称。”

0

你见过NHibernate.Spatial project吗?这可以为您的问题提供一个简单的解决方案。

另一种方法是创建您自己的ICriterion的实现 - 如果您从AbstractCriterion派生出来并且针对特定的数据库平台,这不会太棘手。这将允许您将距离函数与其他标准结合起来。

+0

谢谢约翰,我一直在使用它,但一直未能得到它的工作。 IsWithinDistance似乎没有被执行。我会提出你的第二个建议。 – harriyott 2009-12-03 00:48:44