2009-08-14 48 views

回答

23

使用Projection

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

這個表達式的返回類型是什麼? – IanT8 2010-05-11 03:14:19

+0

一個對象。您可以使用UniqueResult 重載將它轉換爲特定類型。在這種情況下,你會想UniqueResult (),以將其轉換爲整數。 – 2011-01-27 23:54:54

15

MAX(ID)+ 1 '選擇@cus_id =最大客戶(ID)+ 1' 是生成ID的非常糟糕的方式。如果這是您的目標,請找到另一種生成ID的方法。

編輯:在回答LnDCobra:

這是不好的,因爲它很難確保你得到了最大(ID)仍然最大(ID),當你插入。如果另一個進程插入一行,您的插入將具有相同的ID,並且插入將失敗。 (或者相反,如果您的插入先發生,則其他進程的插入將失敗。)

爲了防止出現這種情況,您必須防止其他任何插入/使您的get和後續插入原子,這通常意味着鎖定表,會損害表現。

如果只鎖定對寫入,其他的進程得到最大(ID),這是相同的MAX(ID),你知道的。你做你的插入和釋放鎖,它插入一個重複的ID並失敗。或者它也試圖鎖定,在這種情況下它會等待你。如果你鎖定閱讀,每個人都在等你。如果對鎖定也寫,那麼就不會插入重複的ID,但它並等待您的讀取和寫入的。

(而且它打破封裝:你應該讓RDBMS弄清楚它的ID,而不是連接到它的客戶端程序。)

一般情況下,這種策略之一:
*打破
*需要一串「管道」代碼,使其工作
*顯著降低性能
*或全部三個

,它會比較慢,不太可靠,並且需要更多的努力維護的代碼比只使用內置的序列的RDBMS或生成自動增量ID。

+2

有人點我在正確的方向,爲什麼不利用這個生成的ID,如果有一個更好的辦法...? – 2010-11-05 10:28:41

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