9

基準を使用して t-sql コマンドを実行し、テーブル内の列の最大値を選択できますか?

'select @cus_id = max(id) + 1 from customers'

オリー

4

3 に答える 3

24

投影を使用:

session.CreateCriteria(typeof(Customer))
  .SetProjection( Projections.Max("Id") )
  . UniqueResult();
于 2009-08-14T15:34:41.567 に答える
15

Max(id) + 1 は、id を生成するための非常に悪い方法です。それがあなたの目標である場合は、ID を生成する別の方法を見つけてください。

編集:LnDCobraへの回答:

挿入を行うときに、取得した max(id) がまだ max(id) であることを確認するのが難しいため、これは悪いことです。別のプロセスが行を挿入すると、挿入は同じ ID を持つため、挿入は失敗します。(または、逆に、挿入が最初に行われた場合、他のプロセスの挿入は失敗します。)

これを防ぐには、他の挿入を禁止するか、get とその後の挿入をアトミックにする必要があります。これは通常、テーブルをロックすることを意味し、パフォーマンスが低下します。

書き込みに対してのみロックすると、他のプロセスは max(id) を取得します。これは、取得した max(id) と同じです。挿入を行ってロックを解除すると、重複した ID が挿入されて失敗します。または、ロックも試みます。その場合は、あなたを待ちます。読み取りに対してもロックすると、誰もがあなたを待っています。書き込みに対してもロックする場合は、重複した ID を挿入しませんが、読み取りと書き込みを待機します。

(そして、カプセル化を破ります。接続するクライアント プログラムではなく、rdbms にその ID を理解させる必要があります。)

一般に、この戦略は次のいずれかになります:
* 壊れる
* 機能させるために大量の「配管」コードが必要になる
* パフォーマンスが大幅に低下する
* または 3 つすべて

また、RDBMS の組み込みシーケンスまたは生成された自動インクリメント ID を使用するよりも、遅く、堅牢性が低く、コードの保守がより困難になります。

于 2009-08-14T14:45:32.427 に答える
0

最善の方法は、追加のシーケンス テーブルを作成することです。シーケンスのターゲットと値を維持できる場所。

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

于 2011-12-29T14:38:26.317 に答える