基準を使用して t-sql コマンドを実行し、テーブル内の列の最大値を選択できますか?
'select @cus_id = max(id) + 1 from customers'
タ
オリー
基準を使用して t-sql コマンドを実行し、テーブル内の列の最大値を選択できますか?
'select @cus_id = max(id) + 1 from customers'
タ
オリー
投影を使用:
session.CreateCriteria(typeof(Customer))
.SetProjection( Projections.Max("Id") )
. UniqueResult();
Max(id) + 1 は、id を生成するための非常に悪い方法です。それがあなたの目標である場合は、ID を生成する別の方法を見つけてください。
編集:LnDCobraへの回答:
挿入を行うときに、取得した max(id) がまだ max(id) であることを確認するのが難しいため、これは悪いことです。別のプロセスが行を挿入すると、挿入は同じ ID を持つため、挿入は失敗します。(または、逆に、挿入が最初に行われた場合、他のプロセスの挿入は失敗します。)
これを防ぐには、他の挿入を禁止するか、get とその後の挿入をアトミックにする必要があります。これは通常、テーブルをロックすることを意味し、パフォーマンスが低下します。
書き込みに対してのみロックすると、他のプロセスは max(id) を取得します。これは、取得した max(id) と同じです。挿入を行ってロックを解除すると、重複した ID が挿入されて失敗します。または、ロックも試みます。その場合は、あなたを待ちます。読み取りに対してもロックすると、誰もがあなたを待っています。書き込みに対してもロックする場合は、重複した ID を挿入しませんが、読み取りと書き込みを待機します。
(そして、カプセル化を破ります。接続するクライアント プログラムではなく、rdbms にその ID を理解させる必要があります。)
一般に、この戦略は次のいずれかになります:
* 壊れる
* 機能させるために大量の「配管」コードが必要になる
* パフォーマンスが大幅に低下する
* または 3 つすべて
また、RDBMS の組み込みシーケンスまたは生成された自動インクリメント ID を使用するよりも、遅く、堅牢性が低く、コードの保守がより困難になります。
最善の方法は、追加のシーケンス テーブルを作成することです。シーケンスのターゲットと値を維持できる場所。
public class Sequence : Entity
{
public virtual long? OwnerId { get; set; }
public virtual SequenceTarget SequenceTarget { get; set; }
public virtual bool IsLocked { get; set; }
public virtual long Value { get; set; }
public void GenerateNextValue()
{
Value++;
}
}
public class SequenceTarget : Entity
{
public virtual string Name { get; set; }
}
public long GetNewSequenceValueForZZZZ(long ZZZZId)
{
var target =
Session
.QueryOver<SequenceTarget>()
.Where(st => st.Name == "DocNumber")
.SingleOrDefault();
if (target == null)
{
throw new EntityNotFoundException(typeof(SequenceTarget));
}
return GetNewSequenceValue(ZZZZId, target);
}
protected long GetNewSequenceValue(long? ownerId, SequenceTarget target)
{
var seqQry =
Session
.QueryOver<Sequence>()
.Where(seq => seq.SequenceTarget == target);
if (ownerId.HasValue)
{
seqQry.Where(seq => seq.OwnerId == ownerId.Value);
}
var sequence = seqQry.SingleOrDefault();
if (sequence == null)
{
throw new EntityNotFoundException(typeof(Sequence));
}
// re-read sequence, if it was in session
Session.Refresh(sequence);
// update IsLocked field, so we acuire lock on record
// configure dynamic update , so only 1 field is being updated
sequence.IsLocked = !sequence.IsLocked;
Session.Update(sequence);
// force update to db
Session.Flush();
// now we gained block - re-read record.
Session.Refresh(sequence);
// generate new value
sequence.GenerateNextValue();
// set back dummy filed
sequence.IsLocked = !sequence.IsLocked;
// update sequence & force changes to DB
Session.Update(sequence);
Session.Flush();
return sequence.Value;
}
OwnerId - ある種の所有者に基づいて、同じエンティティに対して異なるシーケンスを維持する必要がある場合。たとえば、契約内のドキュメントの番号付けを維持する必要がある場合、OwnerId will be = contractId