2009-08-14 2 views

ответ

23

Использование Projection:

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

Каков тип возврата из этого выражения? – IanT8

+0

Объект. Вы можете использовать перегрузку UniqueResult , чтобы применить ее к определенному типу. В этом случае вам понадобится UniqueResult (), чтобы передать его целому числу. –

15

Max (ID) + 1 является очень плохой способ для генерации идентификаторов. Если это ваша цель, найдите другой способ создания идентификаторов.

Edit: в ответ на LnDCobra:

это плохо, потому что это трудно, чтобы убедиться, что максимальная (ID) вы получили до сих пор максимальная (идентификатор), когда вы делаете вставку. Если другой процесс вставляет строку, ваша вставка будет иметь тот же идентификатор, и ваша вставка не будет выполнена. (Или, наоборот, вставка другого процесса не будет выполнена, если ваша вставка возникла первой.)

Чтобы предотвратить это, вы должны предотвратить любые другие вставки/сделать ваш get и последующую вставку атомом, что обычно означает блокировку таблицы, что будет ухудшать производительность.

Если вы только блокируете запись, другой процесс получает max (id), который является таким же максимальным (id), который вы получили. Вы вставляете и освобождаете замок, он вставляет дубликат идентификатора и терпит неудачу. Или он пытается запереть, и в этом случае он ждет вас. Если вы запираете и читаете, все вас ждут. Если он также блокирует записи, тогда он не вставляет дубликат идентификатора, но он ждет вашего чтения и вашей записи.

(И это нарушает инкапсуляцию: вы должны позволить РСУБД выяснить свои идентификаторы, а не клиентские программы, которые подключаются к нему.)

В целом, эта стратегия будет либо:
* перерыв
* требуют связка «сантехника» код, чтобы сделать его работу
* значительно снижает производительность
* или все три

и он будет медленнее, менее надежным, и требует более трудно поддерживать код, чем просто с помощью СУБД, построенных в последовательностях или генерируемые идентификаторы автоинкремента.

+2

Может ли кто-нибудь указать мне в правильном направлении, почему бы не использовать это для генерации идентификаторов, и если так, то лучший способ ...? –

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