2011-12-01 14 views
5

¿Cuál es la forma correcta de asignar una columna de marca de tiempo en una base de datos de SQL Server 2008 utilizando las nuevas asignaciones basadas en código de NHibernate?NHibernate 3.2 por código ClassMapping para propiedad de versión

Tengo la propiedad en mi clase define como byte [] y estoy usando el siguiente mapeo en mi archivo ClassMapping:

Version(x => x.RowVersion, mapping => 
    mapping.Generated(VersionGeneration.Always)); 

Sin embargo, NHibernate está esperando un entero en base a esta asignación (se emite una excepción en insertos). Si especifico explícitamente el tipo de mapeo como byte [], obtengo una excepción que dice: "System.ArgumentOutOfRangeException: Tipo esperado que implementa IUserVersionType Nombre del parámetro: persistentType".

¿Cuál es la forma correcta de asignar una columna de fecha y hora de actualización automática con las nuevas asignaciones basadas en el código NHibernate?

--- EDITAR

creo que tengo que redujo que necesito para establecer el tipo en el mapeo de binaryType (un tipo de NHibernate que implementa IVersionType), pero binaryType no tiene un constructor público. .. Creo que estoy sin ideas.

Respuesta

4

También estamos usando byte[] Version { get; } para la implementación de la versión.

Aquí está fuera asignaciones:

Version(x => x.Version) 
      .Nullable() 
      .CustomSqlType("timestamp") 
      .Generated.Always() 
      ; 

también para más detalles, véase this link

+0

Gracias por la respuesta, desafortunadamente no estoy usando Fluent Nhibernate. Solo estoy usando las correlaciones de código incorporadas que son nuevas en 3.2. Las asignaciones de código by incorporadas no tienen un CustomSqlType – wllmsaccnt

5

Si agarras el código fuente NHib, hay una clase en un proyecto de prueba que le ayudará con lo que necesita : NHibernate.Test.VersionTest.Db.MsSQL.BinaryTimestamp. Básicamente, debe darle un tipo personalizado que pueda usar para convertir el valor. Sea predeterminado NHib espera que el valor sea un int (vea la sección 5.1.7 de the nhib docs). Si usa int/bigint como su columna de versión, no necesitará un tipo personalizado.

La clase personalizada (levantado de código fuente NHib):

public class BinaryTimestamp : IUserVersionType 
{ 
    #region IUserVersionType Members 

    public object Next(object current, ISessionImplementor session) 
    { 
     return current; 
    } 

    public object Seed(ISessionImplementor session) 
    { 
     return new byte[8]; 
    } 

    public object Assemble(object cached, object owner) 
    { 
     return DeepCopy(cached); 
    } 

    public object DeepCopy(object value) 
    { 
     return value; 
    } 

    public object Disassemble(object value) 
    { 
     return DeepCopy(value); 
    } 

    public int GetHashCode(object x) 
    { 
     return x.GetHashCode(); 
    } 

    public bool IsMutable 
    { 
     get { return false; } 
    } 

    public object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
     return rs.GetValue(rs.GetOrdinal(names[0])); 
    } 

    public void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
     NHibernateUtil.Binary.NullSafeSet(cmd, value, index); 
    } 

    public object Replace(object original, object target, object owner) 
    { 
     return original; 
    } 

    public System.Type ReturnedType 
    { 
     get { return typeof(byte[]); } 
    } 

    public SqlType[] SqlTypes 
    { 
     get { return new[] { new SqlType(DbType.Binary, 8) }; } 
    } 

    public int Compare(object x, object y) 
    { 
     var xbytes = (byte[])x; 
     var ybytes = (byte[])y; 
     return CompareValues(xbytes, ybytes); 
    } 

    bool IUserType.Equals(object x, object y) 
    { 
     return (x == y); 
    } 

    #endregion 

    private static int CompareValues(byte[] x, byte[] y) 
    { 
     if (x.Length < y.Length) 
     { 
      return -1; 
     } 
     if (x.Length > y.Length) 
     { 
      return 1; 
     } 
     for (int i = 0; i < x.Length; i++) 
     { 
      if (x[i] < y[i]) 
      { 
       return -1; 
      } 
      if (x[i] > y[i]) 
      { 
       return 1; 
      } 
     } 
     return 0; 
    } 

    public static bool Equals(byte[] x, byte[] y) 
    { 
     return CompareValues(x, y) == 0; 
    } 
} 

Un mapeo muestra usando esa clase:

public class Car 
{ 
    public virtual long CarId { get; set; } 
    public virtual string Name { get; set; } 
    public virtual byte[] LastModified { get; set; } 

    public override string ToString() 
    { 
     return string.Format("Id: {0}, Name: {1}, Last Modified: {2}", CarId, Name, LastModified); 
    } 
} 

public class CarMap : ClassMapping<Car> 
{ 
    public CarMap() 
    { 
     Table("Cars"); 

     Id(car => car.CarId, mapper => mapper.Generator(Generators.Identity)); 
     Property(car => car.Name); 
     Version(car => car.LastModified, mapper => 
              { 
               mapper.Generated(VersionGeneration.Always); 
               mapper.Type<BinaryTimestamp>(); 
              }); 
    } 
} 
3

En el caso de un ConventionModelMapper Terminé usando la siguiente ..

ConventionModelMapper mapper = new ConventionModelMapper(); 

//...other mappings 

mapper.Class<Entity>(map => map.Version(e => e.Revision, m => 
       { 
        m.Generated(VersionGeneration.Always); 
        m.UnsavedValue(null); 
        m.Type(new BinaryBlobType()); 
        m.Column(c => 
         { 
          c.SqlType("timestamp"); 
          c.NotNullable(false); 
         }); 
       })); 
Cuestiones relacionadas