我的数据库中有一个存储过程,用于计算两个纬度/经度对之间的距离。该存储过程称为“DistanceBetween”。我有一个 SQL 语句,允许用户搜索 Items 表中的所有项目,这些项目按到提供的纬度/经度坐标的距离排序。 SQL语句如下:
SELECT Items.*, dbo.DistanceBetween(@lat1, @lat2, Latitude, Longitude) AS Distance
FROM Items
ORDER BY Distance
如何在 NHibernate 中使用此查询?我的域中的 Item 类没有“距离”属性,因为我的 Items 表中没有“距离”列。 “距离”属性实际上仅在用户执行此搜索时发挥作用。
最佳答案
基本上可以使用三种方法,其中一些已经讨论过:
- 使用 HQL 查询或
CreateCriteria
/ICriteria
查询; 缺点:它不是实体/DAL 的一部分; 优点:它很灵活; - 使用带有
公式的属性映射
; 缺点:它并不总是可行或可能的,如果不小心,性能可能会下降; 优点:它是计算实体不可分割的一部分; - 创建单独的 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/