4

I have one application which uses NHibernate to save entities to a database, and it uses the HiLo generate of NHibernate to create the id's. I have another application which I need to save data to the same table, however in this application, I'm not using NHibernate. Is there a simple way to use HiLo without adding reference to NHibernate and mapping files?

<id name="EntityId" unsaved-value="0" >
    <column name="EntityId" sql-type="int" not-null="true" />
    <generator class="hilo">
    <param name="table">hibernate_unique_key</param>
        <param name="column">next_hi</param>
        <param name="max_lo">1000</param>
    </generator>
</id>

Update: I created a new method to get the next id which I believe has the same behavior as the NHibernate HiLo sequence. I'm not putting any locks on the database, so if this were a high frequency table that I was inserting to, it could be an issue, but for very low frequency, there is a very low possibility that there may be a concurrency issue.

/// <summary>
/// Gets the next entity id.
/// </summary>
/// <returns></returns>
public static int GetNextAvailableEntityId()
{
    int max_lo = 1000;
    int nextHi = DefaultContext.Database.SqlQuery<int>("select next_hi from hibernate_unique_key").Single();
    int nextRangeStart = max_lo * nextHi;
    int currentMax = DefaultContext.Database.SqlQuery<int>("SELECT MAX(entityid) FROM Entities").Single();

    if (currentMax < nextRangeStart)
    {
        return currentMax + 1;
    }
    else
    {
        DefaultContext.Database.ExecuteSqlCommand("update hibernate_unique_key set next_hi = next_hi + 1");
        return nextHi;
    }
}
mservidio
  • 12,817
  • 9
  • 58
  • 84
  • I suggest posting your NH config for your HiLo columns so that an precise answer can be given, rather than a generalization. In other words, what are your param values? http://stackoverflow.com/questions/2738671/please-explain-nhibernate-hilo/7084697#7084697 – Brook Sep 02 '11 at 14:20
  • I updated the post to include the HiLo configuration... – mservidio Sep 02 '11 at 14:22
  • Just to confirm, you are using the same key table, `hibernate_unique_key` for all of your entities? – Brook Sep 02 '11 at 14:26
  • You could update the title to be more specific. This is probably a common problem. – Stefan Steinegger Sep 02 '11 at 14:47

1 Answers1

4

If in doubt, take a look at NH's code to be sure that you implement it correctly.

It is something like this:

  • open a separate transaction, increment and read the next high value, commit
  • create 1000 ids by next_high * 1000 + x
  • when you run out of ids, start again

You can create a single instance of an id generator for all transaction of the same process. Make sure that your id generator is thread safe.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • Thanks. I'm having a look at this currently: http://nhibernate.svn.sourceforge.net/viewvc/nhibernate/tags/3.2.0GA/nhibernate/src/NHibernate/Id/SequenceHiLoGenerator.cs?revision=6038&view=markup – mservidio Sep 02 '11 at 14:42
  • The part with the separate transaction is not obvious. I hope my answer helps. – Stefan Steinegger Sep 02 '11 at 14:47
  • My implementation above may be slightly different. So NHibernate actually reserves 1000 Id's basically when max_lo is set at 1000. After the transaction is closed, any subsequent transaction has the next thousand available to it? – mservidio Sep 03 '11 at 03:40
  • No, not the transaction has 1000 values available, the whole process (=application) has 1000 values available. If a single transaction only needs one value, you can process 1000 transaction until you run out of ids. That's why you update the hi-lo table in a separate transaction. This generates incremental numbers without gaps, until you restart the application. Then it will increment the next-hi (of course only when at least one id is used). – Stefan Steinegger Sep 03 '11 at 05:25