我的数据库中有一个存储过程,用于计算两个纬度/长度对之间的距离。此存储过程称为“DistanceBetween”。我有一个SQL语句允许用户搜索Items表中按所提供的纬度/经度坐标的距离排序的所有项目。 SQL语句如下:
SELECT Items.*, dbo.DistanceBetween(@lat1, @lat2, Latitude, Longitude) AS Distance
FROM Items
ORDER BY Distance
如何在NHibernate中使用此查询?我的域中的Item类没有“距离”属性,因为我的Items表中没有“距离”列。 “距离”属性实际上仅在用户执行此搜索时才会发挥作用。
答案 0 :(得分:3)
基本上可以使用三种方法,其中一些方法已经讨论过了:
CreateCriteria
/ ICriteria
查询; 缺点:它不是实体/ DAL的一部分; 好处:它很灵活; formula
的属性映射; 缺点:它并不总是可行或可能,如果不小心,性能会降低; 好处:计算是您实体不可分割的一部分; 我将在这里简要展示一个选项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>
如果由于映射限制,缓存问题或者当前缓存设置逐个检索而不是更大量而无法更改,则应该考虑上述情况,您应该考虑另一种方法,例如a整个查询与参数的单独映射。这与上面的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 */
根据您的需要,您可以选择一种方法。我个人使用以下经验法则来决定使用哪种方法:
formula
方法; sql-query
+映射方法; ICriteria
或HQL方法。 关于数据的排序:当您选择“公式”或“sql-query mapping”方法时,您必须在检索数据时进行排序。这与通过当前映射检索数据没有什么不同。
更新:在sql-query XML中更正了严重的编辑错误。
答案 1 :(得分:1)
你可以尝试:
session.CreateSqlQuery(@"SELECT {item.*}, dbo.DistanceBetween(:lat1, :lat2, {item}.Latitude, {item}.Longitude) AS Distance
FROM Items {item}
ORDER BY Distance")
.AddEntity("item", typeof(Item))
.SetDecimal("lat1", lat1)
.SetDecimal("lat2", lat2)
.List<Item>()
NHibernate对于桌子而言非常挑剔查询中的列别名,因此您需要使用{}语法扩展它们。另外,使用HQL命名参数语法(:lat1而不是@ lat1),并将SetDecimal()更改为正确的数据类型。
答案 2 :(得分:0)
Ayende解释了如何在映射文件中执行此操作,而不必诉诸于将SQL传递给您的会话:
http://ayende.com/Blog/archive/2006/09/18/UsingNHibernateWithStoredProcedures.aspx
另请参阅有关此问题的Hibernate文档(也与NHibernate相关):
http://docs.jboss.org/hibernate/stable/core/reference/en/html/querysql.html