sql - NHibernate 查询与距离计算存储过程

标签 sql nhibernate

我的数据库中有一个存储过程,用于计算两个纬度/经度对之间的距离。该存储过程称为“DistanceBetween”。我有一个 SQL 语句,允许用户搜索 Items 表中的所有项目,这些项目按到提供的纬度/经度坐标的距离排序。 SQL语句如下:

SELECT Items.*, dbo.DistanceBetween(@lat1, @lat2, Latitude, Longitude) AS Distance
FROM Items
ORDER BY Distance

如何在 NHibernate 中使用此查询?我的域中的 Item 类没有“距离”属性,因为我的 Items 表中没有“距离”列。 “距离”属性实际上仅在用户执行此搜索时发挥作用。

最佳答案

基本上可以使用三种方法,其中一些已经讨论过:

  1. 使用 HQL 查询或 CreateCriteria/ICriteria 查询; 缺点:它不是实体/DAL 的一部分; 优点:它很灵活;
  2. 使用带有公式的属性映射缺点:它并不总是可行或可能的,如果不小心,性能可能会下降; 优点:它是计算实体不可分割的一部分;
  3. 创建单独的 XML HBM 映射文件并映射到单独的(待创建的)实体; 缺点:它不是基础实体的一部分; 优点:您仅在需要时调用 SP,完全控制映射/额外属性/扩展,可以使用部分或抽象类与现有实体组合。

我将在这里简要展示选项 2 和 3 的示例,我相信选项 1 已被本主题前面的其他人充分介绍。

如本例所示,当查询可以创建为 select 语句的子查询并且所有需要的参数在映射表中可用时,选项二特别有用。如果表不可变和/或缓存为只读,这也会有所帮助,具体取决于存储过程的重量。

<class name="..." table="..." lazy="true" mutable="false>
  <cache usage="read-only" />

    <id name="Id" column="id" type="int">
      <generator class="native" />
    </id>
    <property name="Latitude" column="Latitude" type="double" not-null="true" />
    <property name="Longitude" column="Longitude" type="double" not-null="true" />

    <property name="PrijsInstelling"
        formula="(dbo.DistanceBetween(@lat1, @lat2, Latitude, Longitude))"
        type="double" />

    ... etc
</class>

如果由于映射限制、缓存问题而无法实现上述操作,或者如果您当前的缓存设置是逐个检索而不是大量检索并且您无法更改它,则应考虑采用替代方法,例如整个查询与参数的单独映射。这与上面的 CreateSqlQuery 方法非常接近,但强制结果集为某种类型(并且您可以以声明方式设置每个属性):

<sql-query flush-mode="never" name="select_Distances">
    <return
        class="ResultSetEntityClassHere,Your.Namespace"
        alias="items"
        lock-mode="read" >

        <return-property name="Id" column="items_Id" />
        <return-property name="Latitude" column="items_Latitude" />
        <return-property name="Longitude" column="items_Longitude" />
        <return-property name="Distance" column="items_Distance" />
    </return>

    SELECT 
        Items.*, 
        dbo.DistanceBetween(@lat1, @lat2, Latitude, Longitude) AS Distance
    FROM Items
    WHERE UserId = :userId

</sql-query>

您可以按如下方式调用此查询:

List<ResultSetEntityClassHere> distanceList = 
    yourNHibernateSession.GetNamedQuery("select_Distances") 
        .SetInt32("userId", currentUserId)  /* any params go this way */
        .SetCacheable(true)                 /* it's usually good to cache */
        .List<ResultSetEntityClassHere>();  /* must match the class of sql-query HBM */

根据您的需求,您可以选择一种方法。我个人使用以下经验法则来决定使用哪种方法:

  • 计算量轻还是可以缓存? 使用公式方法;
  • 是否需要向SP/SQL发送参数? 使用sql-query+映射方法;
  • 查询的结构(非常)可变吗? 通过代码使用ICriteria或HQL方法。

关于数据的排序:当您选择“公式”或“sql-查询映射”方法时,您必须在检索数据时进行排序。这与通过当前映射检索数据没有什么不同。

更新:在 sql 查询 XML 中纠正了可怕的编辑错误。

关于sql - NHibernate 查询与距离计算存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/412022/

相关文章:

c# - 流利的 nhibernate 的分页问题

c# - NHibernate - 它是否适用于外键约束的数据库级级联删除

c# - 将 IList 或 IEnumerable 转换为数组的最佳方法

linq - NHibernate 3.x 在组合 LINQ 分页、多对多和子选择获取时删除子实体

Azure 上的 Nhibernate HiLo

mysql - 如何找到列名长度大于 5 的所有列?

mysql - MySQL如何比较日期时间并获取第一个和最后一个日期

mysql - 在 SQL 中选择行数据和缩放器

mysql - 如何从表格列中选择 4 位数字的组合?

sql - 如何在 SQL 中计算非空/非空白值