NHibernate offers 2 standard generators utilizing SQL Server sequences: 'sequence' and 'seqhilo'. The first is inefficient when saving many objects at once and the second has some problems:
1. dependency is introduced between database and components generating IDs; max_lo must be the same everywhere; if it is changed somewhere, there is no alert and id clash may be postponed until later date when it will become more difficult to fix
2. inserting rows in SQL (e.g. legacy stored procedures) becomes more difficult because hilo algorithm, which is arguably counter-intuitive and tricky, needs to be implemented in pure SQL; if implemented successfully, one more place is thus added where max_lo is defined.
Unfortunately MS SQL syntax for retrieving sequence values does not support batches, you can only get 1 value with 'next value for ...'. But there's a documented stored procedure sys.sp_sequence_get_range which does exactly what we need: leaving sequence returning exact IDs (not a value from which ID needs to be calculated using configuration stored elsewhere), it generates arbitrary number of IDs at once. So why not use it in a custom generator:
and then in hbm:
<id name="Id" type="Int64">
<column name="Id" not-null="true" />
<generator class="SqlServerSequenceIdGenerator, MyAssembly">
<param name="SequenceName">dbo.MyTableId</param>
<param name="CacheSize">100</param>
</generator>
</id>
or fluent (unverified):
Identity.GeneratedBy.Custom<SqlServerSequenceIdGenerator>(b => b.AddParam("SequenceName", "dbo.MyTableId").AddParam("CacheSize", "100"));
1. dependency is introduced between database and components generating IDs; max_lo must be the same everywhere; if it is changed somewhere, there is no alert and id clash may be postponed until later date when it will become more difficult to fix
2. inserting rows in SQL (e.g. legacy stored procedures) becomes more difficult because hilo algorithm, which is arguably counter-intuitive and tricky, needs to be implemented in pure SQL; if implemented successfully, one more place is thus added where max_lo is defined.
Unfortunately MS SQL syntax for retrieving sequence values does not support batches, you can only get 1 value with 'next value for ...'. But there's a documented stored procedure sys.sp_sequence_get_range which does exactly what we need: leaving sequence returning exact IDs (not a value from which ID needs to be calculated using configuration stored elsewhere), it generates arbitrary number of IDs at once. So why not use it in a custom generator:
and then in hbm:
<id name="Id" type="Int64">
<column name="Id" not-null="true" />
<generator class="SqlServerSequenceIdGenerator, MyAssembly">
<param name="SequenceName">dbo.MyTableId</param>
<param name="CacheSize">100</param>
</generator>
</id>
or fluent (unverified):
Identity.GeneratedBy.Custom<SqlServerSequenceIdGenerator>(b => b.AddParam("SequenceName", "dbo.MyTableId").AddParam("CacheSize", "100"));