2009-08-14 10 views

Odpowiedz

23

Zastosowanie Projection:

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

Jaki jest typ zwracany z tego wyrażenia? – IanT8

+0

Obiekt. Możesz użyć przeciążenia UniqueResult , aby przesłać go do określonego typu. W takim przypadku będziesz potrzebował UniqueResult (), aby przesłać go do liczby całkowitej. –

15

Max (id) + 1 jest bardzo zły sposób generowania identyfikatorów. Jeśli to jest twój cel, znajdź inny sposób generowania identyfikatorów.

Edycja: W odpowiedzi na LnDCobra:

to jest złe, bo trudno, aby upewnić się, że max (id) masz nadal jest max (id), kiedy robisz wkładkę. Jeśli inny proces wstawi wiersz, twoja wstawka będzie miała ten sam identyfikator, a twoja wstawka się nie powiedzie. (Albo, odwrotnie, wstawienie drugiego procesu nie powiedzie się, jeśli twoja wstawka wydarzyła się jako pierwsza.)

Aby temu zapobiec, musisz zapobiegać jakimkolwiek innym wstawkom/sprawić, że twoje wejście i kolejna wstawka atomowa, co zwykle oznacza zablokowanie stołu, co zaszkodzi wydajności.

Jeśli blokujesz tylko zapisy, drugi proces otrzymuje max (id), który jest tym samym maks. (Identyfikatorem), jaki masz. Robisz wkładkę i zwalniasz blokadę, wstawia ona duplikat id i kończy się niepowodzeniem. Lub też próbuje się zablokować, w takim przypadku czeka na ciebie. Jeśli zablokujesz też czytanie, wszyscy na ciebie czekają. Jeśli blokuje się również przed zapisami, to nie wstawia duplikatu id, ale czeka na odczyt i zapis.

(I to łamie enkapsulacji: należy pozwolić RDBMS wymyślić swoje identyfikatory, a nie programy klienckie łączące się z nim).

Generalnie, strategia ta będzie albo:
* złamać
* wymagają pęczek „hydraulika” kodu, aby to działało
* znacznie obniżyć wydajność
* lub wszystkie trzy

i będzie wolniejszy, mniej wytrzymałe i wymagają bardziej trudne do utrzymania kodu niż tylko przy użyciu RDBMS zbudowany w sekwencjach lub wygenerowane identyfikatory autoregulacji.

+2

Czy ktoś może wskazać mi właściwy kierunek, dlaczego nie użyć tego do wygenerowania identyfikatora, a jeśli tak, to lepiej ...? –

0

najlepszym rozwiązaniem jest, aby dodatkowe sekwencje tabeli. Gdzie można zachować cel sekwencji i wartość.

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 - gdy zachodzi potrzeba zachowania różnych sekwencji dla tego samego podmiotu, w zależności od właściciela. Na przykład musisz zachować numerację dokumentu w ramach umowy, a następnie: OwnerId will be = contractId

Powiązane problemy