Czy mogę użyć Kryteriów, aby wykonać polecenie t-sql, aby wybrać maksymalną wartość dla kolumny w tabeli?Kryteria Nhibernate: "wybierz max (id) ..."
"wybierz @cus_id = max (id) + 1 od klienta
Ta
Nr
Czy mogę użyć Kryteriów, aby wykonać polecenie t-sql, aby wybrać maksymalną wartość dla kolumny w tabeli?Kryteria Nhibernate: "wybierz max (id) ..."
"wybierz @cus_id = max (id) + 1 od klienta
Ta
Nr
Zastosowanie Projection:
session.CreateCriteria(typeof(Customer))
.SetProjection(Projections.Max("Id"))
. UniqueResult();
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.
Czy ktoś może wskazać mi właściwy kierunek, dlaczego nie użyć tego do wygenerowania identyfikatora, a jeśli tak, to lepiej ...? –
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
Jaki jest typ zwracany z tego wyrażenia? – IanT8
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. –