[INFO] NHibernate storedproc params mapping (ord NOT req)
От: снежок Россия  
Дата: 20.06.08 09:23
Оценка:
В документации и статьях описано как произвести маппинг объектов на хранимые процедуры (CRUD).
Описано также что существуют некоторые ограничения, так например, порядок следования параметров в хп должен соответветствовать порядку в котором NHibernate генерит запрос к БД.
Исходя из этого чато делаются выводы:
1. что с помощью NHibernate можно организовать маппинга на хп, если они (хп) создаются с "чистого листа" и если определять параметры в хп в том же порядке в котором генерит NHibernate.
2. NHibernate не подходит для маппинга объектов на хп, разработанные без оглядки на NHibernate

Однако, это не совсем так, по крайней мере для MSSQL.
MSSQL поддерживает синтаксис вызова хп, в котором можно явно задать имя параметра, таким образом, порядок следования параметров в синтаксисе вызова не обязательно должен соответствовать порядку параметров в определении хп.
пример, подобного синтаксиса:
/*exec @RET_CODE = CreateDocument*/
  exec CreateDocument
       @Title           = ?
      ,@FileName        = ?
      ,@FileExtension   = ?
      ,@Revision        = ?
      ,@ChangeNumber    = ?
      ,@Status          = ?
      ,@DocumentSummary = ?
      ,@ModifiedDate    = ?
      ,@DocumentID      = ?

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


CREATE PROCEDURE CreateDocument(
--<ParamDefBlock>
 @DocumentID                      int                   = null out
,@Title                           nvarchar(50)          = null
,@FileName                        nvarchar(400)         = null
,@FileExtension                   nvarchar(8)           = null
,@Revision                        nchar(5)              = null
,@ChangeNumber                    int                   = null
,@Status                          tinyint               = null
,@DocumentSummary                 nvarchar(Max)         = null
,@ModifiedDate                    datetime              = null
--</ParamDefBlock>
)
AS
BEGIN
    SET NOCOUNT ON
    --<DeclareBlock>
    --<DeclareSysVarBlock>
    declare     
             @RET_CODE            int
            ,@ERROR_CODE            int
            ,@TRAN_CHECK            int
    --</DeclareSysVarBlock>
    --<DeclareVarBlock>
    --</DeclareVarBlock>
    --</DeclareBlock>
    --<PrepareTranBlock>
    set @TRAN_CHECK    = case when @@TRANCOUNT > 0 or @@OPTIONS & 2 > 0 then 1 else 0 end
    select    
             @RET_CODE        = 0
            ,@ERROR_CODE    = 0
    if @TRAN_CHECK = 0 BEGIN TRAN
    --</PrepareTranBlock>
    
    --<InsertBlock>
    INSERT INTO Production.Document(Title, FileName, FileExtension, Revision, ChangeNumber, Status, DocumentSummary, ModifiedDate)
                VALUES(@Title, @FileName, @FileExtension, @Revision, @ChangeNumber, @Status, @DocumentSummary, @ModifiedDate)
    --</InsertBlock>
    
    set @ERROR_CODE = @@ERROR
    if (@ERROR_CODE <> 0) or (@RET_CODE <> 0) GOTO UNDO
    --<SuccBlock>
    SUCC:
            SET @DocumentID = SCOPE_IDENTITY()
            SELECT @DocumentID as DocumentID
        if (@TRAN_CHECK = 0) and (@@TRANCOUNT > 0) COMMIT TRAN
        RETURN(0)
    --</SuccBlock>

    --<UndoBlock>
    UNDO:
        if (@@TRANCOUNT > 0)
            if @TRAN_CHECK = 0 ROLLBACK TRAN 
        RETURN(1)
    --</UndoBlock>
END


Маппинг в NHibernate может выглядеть так, как показано ниже.
В определении маппинга используем синтаксис с явным определением имен параметров.
Параметр, соответствующий id (DocumentID) определяем последним в списке (так требуется для корректной работы NHibernate).
Порядок параметров при вызове из NHibernate не соответствует порядку параметров в определении хп, однако решение работоспособно и мы добились некоторой развязки NHibernate и хп.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="WebApplication.Document, WebApplication" table="Production.Document">
    <id name="DocumentID" column="DocumentID">
      <generator class="identity" />
    </id>
    <property name="Title" />
    <property name="FileName" />
    <property name="FileExtension" />
    <property name="Revision" />
    <property name="ChangeNumber" />
    <property name="Status" />
    <property name="DocumentSummary" />
    <property name="ModifiedDate" />
    <property name="DocumentID" />
    <sql-insert check="none">
      exec xsp_Ins_Document 
       @Title           = ?
      ,@FileName        = ?
      ,@FileExtension   = ?
      ,@Revision        = ?
      ,@ChangeNumber    = ?
      ,@Status          = ?
      ,@DocumentSummary = ?
      ,@ModifiedDate    = ?
      ,@DocumentID      = ?
    </sql-insert>
  </class>
</hibernate-mapping>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.