Created
September 19, 2012 10:07
-
-
Save rdingwall/3748819 to your computer and use it in GitHub Desktop.
StandaloneSeqHiloGenerator - ported from NHibernate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Data; | |
using System.Data.Common; | |
using System.Data.SqlTypes; | |
using System.Runtime.CompilerServices; | |
using Oracle.DataAccess.Client; | |
namespace Foo | |
{ | |
/// <summary> | |
/// Ported from NHibernate's SequenceHiLoGenerator - an ID generator that | |
/// combines a hi/lo algorithm with an underlying oracle-style sequence | |
/// that generates hi values. | |
/// </summary> | |
public class StandaloneSeqHiloGenerator | |
{ | |
private readonly string sequenceName; | |
private readonly int maxLo; | |
private readonly SqlString sql; | |
private int lo; | |
private long hi; | |
public string SequenceName | |
{ | |
get { return sequenceName; } | |
} | |
public StandaloneSeqHiloGenerator(string sequenceName, int maxLo) | |
{ | |
if (String.IsNullOrWhiteSpace(sequenceName)) | |
throw new ArgumentException("A sequence name is required.", "sequenceName"); | |
this.sequenceName = sequenceName; | |
this.maxLo = maxLo; | |
lo = maxLo + 1; // so we "clock over" on the first invocation | |
sql = new SqlString(String.Format("select {0}.nextval from dual", sequenceName)); | |
} | |
[MethodImpl(MethodImplOptions.Synchronized)] | |
public long Generate(OracleConnection connection) | |
{ | |
if (connection == null) throw new ArgumentNullException("connection"); | |
if (maxLo < 1) | |
{ | |
//keep the behavior consistent even for boundary usages | |
var val = Convert.ToInt64(GetNextVal(connection)); | |
if (val == 0) | |
val = Convert.ToInt64(GetNextVal(connection)); | |
return val; | |
} | |
if (lo > maxLo) | |
{ | |
var hival = Convert.ToInt64(GetNextVal(connection)); | |
lo = 1; | |
hi = hival * (maxLo + 1); | |
} | |
return hi + lo++; | |
} | |
private object GetNextVal(OracleConnection connection) | |
{ | |
try | |
{ | |
using (var cmd = connection.CreateCommand()) | |
{ | |
cmd.CommandType = CommandType.Text; | |
cmd.CommandText = sql.ToString(); | |
return cmd.ExecuteScalar(); | |
} | |
} | |
catch (DbException sqle) | |
{ | |
throw new Exception(String.Format("could not get next sequence value from {0}", sequenceName), sqle); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using NUnit.Framework; | |
using Oracle.DataAccess.Client; | |
using SharpTestsEx; | |
namespace Foo.Tests | |
{ | |
public class StandaloneSeqHiloGeneratorTests | |
{ | |
[TestFixture, Category("Integration")] | |
public class When_generating_ids | |
{ | |
[Test] | |
public void It_should_generate_new_ids() | |
{ | |
var generator = new StandaloneSeqHiloGenerator("test_seq", maxLo: 10); | |
var builder = new OracleConnectionStringBuilder | |
{ | |
DataSource = "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=10000)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)))", | |
UserID = "....", | |
Password = "..." | |
}; | |
using (var connection = new OracleConnection(builder.ConnectionString)) | |
{ | |
connection.Open(); | |
var initialValue = generator.Generate(connection); | |
var nextValue = generator.Generate(connection); | |
nextValue.Should().Be(initialValue + 1); | |
for (var i = 0; i < 19; i++) | |
nextValue = generator.Generate(connection); | |
nextValue.Should().Be.GreaterThan(initialValue + 20); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment