2009-08-14 22 views

Respuesta

23

Uso Projection:

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

¿Cuál es el tipo de retorno de esta expresión? – IanT8

+0

Un objeto. Puede usar la sobrecarga UniqueResult para convertirla a un tipo específico. En este caso, querrá UniqueResult () para convertirlo a un número entero. –

15

Max (ID) + 1 es una muy mala manera de generar los identificadores. Si ese es tu objetivo, busca otra forma de generar identificadores.

Editar: en respuesta a LnDCobra:

es malo porque es duro para asegurarse de que el máximo (ID) que obtuvo sigue siendo el máximo (ID) cuando lo hace el inserto. Si otro proceso inserta una fila, su inserción tendrá la misma identificación, y su inserción fallará. (O, por el contrario, la inserción del otro proceso fallará si su inserción sucedió primero.)

Para evitar esto, debe evitar cualquier otra inserción/hacer su inserción atomic y posterior, lo que generalmente significa bloquear la mesa, que perjudicará el rendimiento.

Si solo bloquea contra escrituras, el otro proceso obtiene max (id), que es el mismo máximo (id) que obtuvo. Usted hace su inserción y suelta el candado, inserta una identificación duplicada y falla. O intenta cerrarse también, en cuyo caso te espera. Si bloquea las lecturas también, todo el mundo lo espera. Si también se bloquea contra escrituras, no inserta la identificación duplicada, pero espera en su lectura y escritura.

(y se rompe la encapsulación: usted debe dejar que los RDBMS averiguar sus identificaciones, no los programas cliente que se conectan a ella.)

En general, esta estrategia ya sea:
* romper
* requieren una montón de código "fontanería" para hacer que funcione
* reducir significativamente el rendimiento
* o los tres

y será más lento, menos robusto, y requieren más difícil mantener el código que simplemente usar la década de RDBMS construidas en secuencias o identificadores de autoincrement generados.

+2

¿Puede alguien indicarme las direcciones correctas de por qué no usar esto para generar identificaciones, y si es así una mejor manera ...? –

0

mejor enfoque es hacer tabla secuencias adicionales. Donde puede mantener el objetivo de secuencia y el valor.

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 - cuando necesite mantener secuencias diferentes para la misma entidad, basadas en algún tipo de propietario. Por ejemplo, necesita mantener la numeración del documento dentro del contrato, luego OwnerId will be = contractId

Cuestiones relacionadas