2009-08-14 11 views

答えて

23

session.CreateCriteria(typeof(Customer)) 
    .SetProjection(Projections.Max("Id")) 
    . UniqueResult(); 
+1

この式の戻り値の型は何ですか? – IanT8

+0

オブジェクトです。あなたは、特定の型にキャストするUniqueResult オーバーロードを使用することができます。この場合、あなたはUniqueResult ()は整数にキャストしたいと思います。 –

15

マックス(ID)+ 1

の顧客から@cus_id選択= MAX(ID)+ 1 'は、IDを生成するために非常に悪い方法です。それがあなたの目標なら、IDを生成する別の方法を見つけてください。

編集:LnDCobraへの答えに:それはあなたが挿入を行うときにあなたが得た最大(ID)がまだMAX(ID)であることを確認するのは難しいので、

それが悪いです。別のプロセスが行を挿入した場合、挿入されるIDは同じになり、挿入が失敗します。 (逆に、挿入が最初に起こった場合、他のプロセスの挿入は失敗します)。

これを防ぐには、他の挿入を禁止する必要があります。パフォーマンスを傷つけるでしょう。

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

は(そして、それはカプセル化を壊す:あなたはRDBMSがそのIDSはなく、それに接続するクライアントプログラムを把握するようにする必要があります。)

一般的に、この戦略はどちらかになります。
*
*が必要破りますそれは
*を動作させるために「配管」コードの束が大幅にパフォーマンス
*または3つすべて

を削減し、それが、遅くあまり堅牢で、ちょうどシーケンスに建てられたのRDBMSのを使用するよりも、コードを維持するために、より多くのハードが必要になりますまたは生成された自動インクリメントID。使用Projection

+2

誰かがより良い方法をidを生成するためにこれを使用し、そうでない場合は理由として、右方向に私を指すことができますか...? –

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