代码之家  ›  专栏  ›  技术社区  ›  Jeff

nhibernate-存储过程和复合密钥

  •  2
  • Jeff  · 技术社区  · 17 年前

    我正在尝试使用nhibernate将存储过程的输出映射到项目中的对象。

    对象是这样的:

    public class NewContentSearchResult
    {
        public string Name { get; set; }
        public string ContentType { get; set; }
        public int Count { get; set; }
        public int CMIId { get; set; }
        public int FeatureId { get; set; }
    
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
    
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
    

    地图是这样的:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Class.Assembly"
        namespace="Class.Assembly"
        default-lazy="false" default-cascade="none">
      <class name="NewContentSearchResult" mutable="false" check="none">
        <composite-id unsaved-value="none">
          <key-property name="CMIId" type="int" />
          <key-property name="FeatureId" type="int" />
        </composite-id>
        <property name="ContentType" type="string" />
        <property name="Name" type="string" />
        <property name="Count" type="int" />
      </class>
      <sql-query name="spWebGetNewContentBySalesRole">
        <return class="NewContentSearchResult" lock-mode="read">
          <return-property name="Name" column="Name" />
          <return-property name="ContentType" column="FeatureDesc" />
          <return-property name="Count" column="Number" />
          <return-property name="CMIId" column="CMIId" />
          <return-property name="FeatureId" column="FeatureId" />
        </return>
        exec core.spWebGetNewContentBySalesRole :SalesRoleId
      </sql-query>
    </hibernate-mapping>
    

    存储过程调用是正确的,并且我返回SalesRoleID 266的结果(例如):

    CMIId       FeatureDesc       FeatureId     Name       Count
    4000719 Guest Book          12     Charlie Brown    2
    4000719 Audio Guest Book    3      Charlie Brown    1
    

    如果没有组合键(仅使用cmiid),它的工作就很好,除非有两个结果(如上所述)共享cmiid…第二个结果被第一个结果覆盖。

    我必须使用组合键,而cmiid/featureid是逻辑组合。

    当我现在运行这个时,我得到一个例外:

    NHibernate.ADOException: could not execute query
    [ exec core.spWebGetNewContentBySalesRole ? ]
      Name: SalesRoleId - Value: 266
    [SQL: exec core.spWebGetNewContentBySalesRole ?] --->  System.IndexOutOfRangeException: CMIId22_0_.
    
    4 回复  |  直到 15 年前
        1
  •  5
  •   Jeff    17 年前

    好吧,进一步的研究让我相信,在使用存储过程时,在nhibernate中不可能有复合ID。

    为此,我修改了我的SQL以包含rowNumber(),并将其用作一个ID。我只能这样做,因为它是只读的,不向数据库写入数据,但它是为我的目的工作的。

        2
  •  2
  •   Mark Struzinski    17 年前

    在过去,当我使用复合键时,我总是必须为该ID创建一个单独的类,该类的属性与复合键的属性匹配。你试过这个吗?

        3
  •  2
  •   Alex    15 年前

    正如接受的答案中所提到的,我最终使用了rownum函数,在Oracle中使用了一个唯一的行号黑客。后来,我在使用不同参数重用查询时遇到了一个问题。似乎nhibernate记住了这些ID,并希望将它们与新返回的结果关联起来,从而返回不正确的行。我通过将行数与时间戳组合来修复此问题:

    (ROWNUM * 10000000000 + dbms_utility.get_time) AS ROW_ID
    

    这样,每次查询结果都会得到全新的ID。只需确保使用足够大的整数来保存映射对象中的值。我用 ulong 在C.NET中,它是8个字节。您还可以从乘数中取出一些0来缩短ID。

        4
  •  1
  •   Joe Field    15 年前

    今天有点晚了,但我可以在马克·斯特鲁津斯基之后——这是可能的。

    我最近遇到了这个问题,并通过使用组合键的单独类和映射中的元素来解决它,如下所示。

    <sql-query name="spWebGetNewContentBySalesRole" >
        <return class="NewContentSearchResult">
            <return-property name="NewContentSearchResultKey">
                <return-column name="CMIIdColumn" />
                <return-column name="FeatureIdColumn" />
            </return-property>
            <return-property name="Name" column="Name" />       
            <return-property name="ContentType" column="FeatureDesc" />       
            <return-property name="Count" column="Number" />       
        </return>
        exec core.spWebGetNewContentBySalesRole :SalesRoleId 
    </sql-query>
    

    请注意,返回列元素中的“name”属性表示结果集中的名称,其顺序应与ID类中的属性相同。

    推荐文章