-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: Possible solution for trigger-generated PK values in Oracle
PostPosted: Sun Oct 14, 2007 5:12 pm 
Beginner
Beginner

Joined: Sat Jul 21, 2007 3:56 pm
Posts: 27
I have been able to get NHibernate to work with Oracle databases of which the primary key values are automatically generated in the before-insert triggers, e.g.:

Code:
TRIGGER "NIEK"."ORGANISATION_BEFORE_INSERT"
  BEFORE
  INSERT
  for each row
DECLARE

BEGIN -- executable part starts here

  select NIEK.ORGAN_ORGANID_SEQ.nextval into :new.ORGANISATIONID from dual;

END;


But unfortunately not without having to modify NHibernate's code itself.

I have tried different strategies but the problem that always came back was the fact that Oracle needs a parameter to send back anything from the insert statement. But, even with a custom dialect, I haven't been able to define my own parameter on the command object in the current version of NHibernate.

So I solved the problem by adding a method "IsReturnIdentityViaParameter" in NHibernate's Dialect class:
Code:
public virtual bool IsReturnIdentityViaParameter()
{
    return false;
}


... and extended the AbstractEntityPersister's Insert method to make use of it:

Code:
                       
if (Dialect.IsReturnIdentityViaParameter())
{
    IDbDataParameter identityParameter = insertSelect.CreateParameter();
    identityParameter.ParameterName = ":id";
    identityParameter.DbType = DbType.Int64;
    identityParameter.Direction = ParameterDirection.ReturnValue;

    insertSelect.Parameters.Add(identityParameter);

    session.Batcher.ExecuteNonQuery(insertSelect);
    return identityParameter.Value;
}
else
{
    rs = session.Batcher.ExecuteReader(insertSelect);
    return GetGeneratedIdentity(obj, session, rs);
}


As a result, an output parameter with the name ":id" will be created if the dialect's "IsReturnIdentityViaParameter" method returns true.

So now I can make a custom dialect that returns true in its overridden "IsReturnIdentityViaParameter" method and adds "returning " + identityColumn + " into :id" to the insert statement so that the parameter actually gets populated with the newly generated id:

Code:
using NHibernate.Dialect;
using NHibernate.SqlCommand;

namespace Framework.Dialect
{
    public class IdentityColumnOracleDialect : OracleDialect
    {
        public override bool SupportsIdentityColumns
        {
            get
            {
                return true;
            }
        }

        public override SqlString AddIdentitySelectToInsert(SqlString insertSql, string identityColumn, string tableName)
        {
            return insertSql.Append(" " + GetIdentitySelectString(identityColumn, tableName));
        }

        public override string GetIdentitySelectString(string identityColumn, string tableName)
        {
            return "returning " + identityColumn + " into :id";
        }

        public override bool  IsReturnIdentityViaParameter()
        {
            return true;
        }

    }
}


Don't forget to specify it in the hibernate.fg.xml file:

Code:
    <property name="hibernate.dialect">Framework.Dialect.IdentityColumnOracleDialect,Framework</property>


If everyone is ok with this solution, is there a procedure to request NHibernate's source code to be adapted?

Thanks for any advice,

TolomaĆ¼s.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.