nHibernate - хранимые процедуры и составные ключи

Я пытаюсь сопоставить вывод хранимой процедуры с объектом в моем проекте с помощью 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) он работает нормально, за исключением случаев, когда есть 2 результата (как указано выше), которые используют CMIId ... второй перезаписывается первым.

Мне нужно использовать составной ключ, и CMIId / FeatureId - это логическая комбинация.

Когда я запускаю это сейчас, я получаю исключение:

NHibernate.ADOException: could not execute query
[ exec core.spWebGetNewContentBySalesRole ? ]
  Name: SalesRoleId - Value: 266
[SQL: exec core.spWebGetNewContentBySalesRole ?] --->  System.IndexOutOfRangeException: CMIId22_0_.

person Jeff    schedule 08.07.2009    source источник


Ответы (4)


Хорошо, дальнейшие исследования убедили меня в том, что в nHibernate невозможно иметь составные идентификаторы при использовании хранимой процедуры.

С этой целью я изменил свой SQL, включив rownumber (), и использую его как идентификатор. Я могу сделать это только потому, что он доступен только для чтения, без записи в базу данных, но он работает для моих целей.

person Jeff    schedule 08.07.2009
comment
Не могли бы вы опубликовать полученный код и сопоставления? Я пытаюсь сделать то же самое, но получаю сообщение об ошибке. - person Megacan; 25.09.2009
comment
Отображение просто добавляет поле «id», которое НЕ является составным идентификатором, а в SQL просто «rownumber () as id» в качестве первого параметра. - person Jeff; 28.09.2009
comment
Спасибо, у меня это сработало. Я потратил несколько часов, пытаясь сделать это с отдельным классом, но продолжал получать ошибки. Использовал функцию ROWNUM в Oracle, и это сработало отлично! - person Alex; 11.04.2011

Раньше, когда я использовал составной ключ, мне всегда приходилось создавать отдельный класс для этого идентификатора со свойствами класса, соответствующими отдельным ключам для составного ключа. Вы пробовали это?

person Mark Struzinski    schedule 08.07.2009

Как упоминалось в принятом ответе, в итоге я использовал взлом уникального номера строки в Oracle с помощью функции ROWNUM. Позже я столкнулся с проблемой при повторном использовании запроса с другими параметрами. Похоже, nHibernate запомнил идентификаторы и хотел связать их с вновь возвращенными результатами, возвращая тем самым неправильные строки. Я исправил это, объединив номер строки с меткой времени следующим образом:

(ROWNUM * 10000000000 + dbms_utility.get_time) AS ROW_ID

Таким образом, вы гарантированно будете каждый раз получать совершенно новые идентификаторы для результатов запроса. Просто убедитесь, что вы используете достаточно большое целое число для хранения значения в отображаемом объекте. Я использую ulong в С # .net, который составляет 8 байтов. Вы также можете убрать несколько нулей из множителя, чтобы ID короче.

person Alex    schedule 25.04.2011

Немного поздно, но я могу подкрепить Марка Струзински - это возможно.

Недавно я столкнулся с этой проблемой и решил ее, используя отдельный класс для составного ключа и элементы в сопоставлении следующим образом.

<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.

person Joe Field    schedule 14.10.2010