Puis-je utiliser un critère pour exécuter une commande T-SQL pour sélectionner la valeur max pour une colonne dans une table? P>
'Sélectionnez @CUS_ID = Max (ID) + 1 des clients P>
ta p>
Ollie P>
3 Réponses :
max (id) + 1 est un très mauvais moyen de générer des identifiants. Si c'est votre objectif, trouvez une autre façon de générer des identifiants. P>
Edit: En réponse à LNDCOBRA: P>
C'est mauvais parce qu'il est difficile de s'assurer que le max (ID) que vous avez est toujours le max (ID) lorsque vous effectuez l'insert. Si un autre processus insère une ligne, votre insert aura le même ID et votre insert échouera. (Ou, à l'inverse, l'insert de l'autre processus échouera si votre insert s'est produit en premier.) P>
Pour éviter cela, vous devez empêcher tout autre inserts / faire votre get et votre insertion ultérieure atomique, ce qui signifie généralement verrouiller la table, ce qui nuira aux performances. p>
Si vous verrouillez uniquement contre les écrivies, l'autre processus obtient max (ID), qui est le même max (ID) que vous avez obtenu. Vous faites votre insertion et relâchez la serrure, elle insère un identifiant en double et échoue. Ou il essaie de verrouiller aussi, auquel cas il vous attend sur vous. Si vous vous serrez également contre des lectures, tout le monde vous attend. Si elle se verrouille également contre les écrivies, elle n'entre pas l'identifiant en double, mais cela attend votre lecture et votre écriture. P>
(et il brise l'encapsulation: vous devez laisser les SGBDM à déterminer ses identifiants, pas les programmes clients qui se connectent.) P>
En règle générale, cette stratégie sera soit:
* casser
* nécessite un tas de code "plomberie" pour le faire fonctionner
* Réduire de manière significative les performances de
* ou tous les trois p>
Et il sera plus lent, moins robuste et nécessitera plus de difficulté à gérer le code que d'utiliser uniquement les séquences intégrées de la SGBMS ou des identifiants automobiles générés. P>
Quelqu'un peut-il me signaler dans les bonnes directions pourquoi ne pas utiliser cela pour générer des identifiants, et si oui une meilleure façon ...?
Utilisez Projection :
session.CreateCriteria(typeof(Customer)) .SetProjection( Projections.Max("Id") ) . UniqueResult();
Quel est le type de retour de cette expression?
Un objet. Vous pouvez utiliser la surcharge omeresult
La meilleure approche consiste à faire une table supplémentaire de séquences. Où vous pouvez maintenir la cible de séquence et la valeur.
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; }