40

Cuando estableces un valor de cadena en NHibernate con fluidez, siempre establece los valores de DB en Nvarchar (255), necesito almacenar una gran cantidad de una cadena larga que se basa en las entradas del usuario y 255 no es práctica.Anulación de NHibernate con fluidez para cadenas de texto largas nvarchar (MAX) no nvarchar (255)

Solo para agregar esto es un problema con el Automapper ya que estoy usando NHibernate con fluidez para construir la base de datos.

Respuesta

33

La adición de esta convención fijará la longitud predeterminada para las propiedades de cadena a 10000. Como otros han notado, esta será una columna nvarchar (max).

public class StringColumnLengthConvention : IPropertyConvention, IPropertyConventionAcceptance 
{ 
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) 
    { 
     criteria.Expect(x => x.Type == typeof(string)).Expect(x => x.Length == 0); 
    } 
    public void Apply(IPropertyInstance instance) 
    { 
     instance.Length(10000); 
    } 
} 

convenios se pueden añadir a una configuración automap como esto:

Fluently.Configure() 
    .Mappings(m => 
     m.AutoMappings.Add(AutoMap.AssemblyOf<Foo>() 
     .Conventions.Add<StringColumnLengthConvention >())) 

Para obtener más información, ver Conventions en el wiki Fluido NHibernate.

+0

Justo lo que estaba buscando, ah y para cualquier otra persona Agregue esta línea al método GetConventions() en el archivo utoPersistenceModelGenerator c.Add (); – TheAlbear

17

Ajuste de la longitud de algo más de 4001 generará un nvarchar (max) ...

.WithLengthOf(10000); 

Vea aquí para más detalles ...

http://serialseb.blogspot.com/2009/01/fluent-nhibernate-and-nvarcharmax.html

+0

Parece que funcionaría para un solo valor de cadena, pero necesito hacer esto para cerrar 300 campos de datos, así que estoy buscando una manera fácil de reemplazar cada nvarchar (255) y configurarlo como un nvarchar (Max) – TheAlbear

6

Con Fluent Nhibernate Automapper, uno se da cuenta rápidamente de que el comportamiento fuera de la caja para columnas varchar es menos que ideal. Primero descubre que cada propiedad de cadena se exportó como varchar (255) y necesita hacer que una columna sea varchar (max). Pero idealmente, no tendrías que hacer que cada cadena sea varchar (max), ¿verdad? De modo que puede seguir ese camino trillado para encontrar la mejor forma de ejercer control sobre el proceso sin romper los diversos patrones elegantes en juego ...

Si desea que las columnas varchar de la base de datos resultantes se especifiquen en diferentes longitudes, busca en las clases de convenciones para hacerlo realidad. Puede tratar de crear condiciones específicas de nombre o, en general, usar algún patrón de denominación que haya detectado dentro de su clase de convención.

Ninguno es ideal. Sobrecargar un nombre con el propósito de indicar una especificación prevista en otra parte del código es desafortunado; su nombre debería ser simplemente un nombre. Tampoco debe modificar el código de convención cada vez que necesite agregar o modificar una propiedad de clase de longitud limitada. Entonces, ¿cómo puedes escribir una clase de convención que te dé el control y te brinde ese control de una manera simple y elegante?

Sería dulce si sólo puede decorar su propiedad como lo hice para la propiedad Body aquí:

using System; 
using MyDomain.DBDecorations; 

namespace MyDomain.Entities { 
    [Serializable] 
    public class Message 
    { 
     public virtual string MessageId { get; set; } 

     [StringLength(4000)] public virtual string Body { get; set; } 
    } 
} 

Si esto podría funcionar, tendríamos el control sobre cada cuerda de forma independiente , y podríamos especificarlo directamente en nuestra entidad.

Antes de comenzar una vorágine de separación de la base de datos de la aplicación, permítanme señalar que esta no es específicamente una directiva de base de datos (me referí a no llamar al atributo 'Varchar'). Prefiero caracterizar esto como un aumento de System.string, y en mi pequeño universo estoy contento con eso. En resumen, quiero una conveniencia!

Para ello, es necesario definir la decoración que queremos utilizar:

using System; 
namespace MyDomain.DBDecorations 
{ 

    [AttributeUsage(AttributeTargets.Property)] 
    public class StringLength : System.Attribute 
    { 
     public int Length = 0; 
     public StringLength(int taggedStrLength) 
     { 
      Length = taggedStrLength; 
     } 
    } 
} 

Por último, tenemos que utilizar una convención de longitud de la cadena de usar la decoración propiedad de la entidad. Esta parte puede no parecer bonita, pero cumple su función, ¡y la buena noticia es que no tendrá que volver a mirarla!

StringColumnLengthConvention.cs:

using System.Reflection; 
using FluentNHibernate.Conventions; 
using FluentNHibernate.Conventions.AcceptanceCriteria; 
using FluentNHibernate.Conventions.Inspections; 
using FluentNHibernate.Conventions.Instances; 

namespace MyMappings 
{ 
    public class StringColumnLengthConvention : IPropertyConvention, IPropertyConventionAcceptance 
    { 
     public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) { criteria.Expect(x => x.Type == typeof(string)).Expect(x => x.Length == 0); } 
     public void Apply(IPropertyInstance instance) 
     { 
      int leng = 255; 

      MemberInfo[] myMemberInfos = ((PropertyInstance)(instance)).EntityType.GetMember(instance.Name); 
      if (myMemberInfos.Length > 0) 
      { 
       object[] myCustomAttrs = myMemberInfos[0].GetCustomAttributes(false); 
       if (myCustomAttrs.Length > 0) 
       { 
        if (myCustomAttrs[0] is MyDomain.DBDecorations.StringLength) 
        { 
         leng = ((MyDomain.DBDecorations.StringLength)(myCustomAttrs[0])).Length; 
        } 
       } 
      } 
      instance.Length(leng); 
     } 
    } 
} 

Añadir esta convención a la configuración automapping y ahí lo tienes IT siempre que lo desee una longitud específica que resulte durante ExportSchema, ahora sólo puede decorar la propiedad de cadena -y sólo esa propiedad, ¡justo en tu entidad!

+0

Me gusta de esta manera, así que podemos establecer una longitud máxima específica para una propiedad de cadena, pero vi que alguien dice que rompe POCO, pero no me importa. Creo que puede mejorar esto usando 'AttributePropertyConvention ' y solo 1 línea de código 'leng = ((MyDomain.DBDecorations.StringLength) (myCustomAttrs [0])). Length; 'debe usarse en su lugar. – CallMeLaNN

1

Probablemente usted está utilizando "NHibernate validator" también. En caso afirmativo, Fluido NHibernate tendrá en cuenta todos los datos relacionados con el validador anotaciones NHibernate automáticamente, incluyendo longitud de la cadena, no es nulo, etc.

3

Una de las manera consistente que he encontrado es:

Map(x => x.LongText, "LongText").CustomType<VarcharMax>().Nullable(); 

en la que el VarcharMax y las clases son

public class VarcharMax : BaseImmutableUserType<String> 
{ 
    public override object NullSafeGet(IDataReader rs, string[] names, object owner) 
    { 
     return (string)NHibernateUtil.String.NullSafeGet(rs, names[0]); 
    } 
    public override void NullSafeSet(IDbCommand cmd, object value, int index) 
    { 
     //Change the size of the parameter 
     ((IDbDataParameter)cmd.Parameters[index]).Size = int.MaxValue; 
     NHibernateUtil.String.NullSafeSet(cmd, value, index); 
    } 
    public override SqlType[] SqlTypes 
    { 
     get { return new[] { new SqlType(DbType.String) }; } 
    } 
} 

public abstract class BaseImmutableUserType<T> : NHibernate.UserTypes.IUserType 
{ 
    public abstract object NullSafeGet(IDataReader rs, string[] names, object owner); 
    public abstract void NullSafeSet(IDbCommand cmd, object value, int index); 
    public abstract SqlType[] SqlTypes { get; } 

    public new bool Equals(object x, object y) 
    { 
     if (ReferenceEquals(x, y)) 
     { 
      return true; 
     } 
     if (x == null || y == null) 
     { 
      return false; 
     } 

     return x.Equals(y); 
    } 

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

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

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

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

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

    public Type ReturnedType 
    { 
     get { return typeof(T); } 
    } 

    public bool IsMutable 
    { 
     get { return false; } 
    } 
} 
2

Hola, me encontré con esta pregunta, con el mismo problema. Tengo una manera ligeramente segura de de hacerlo, ya que no quiero que todos los campos de cadena tengan 10000 caracteres por defecto.

En primer lugar me registro nhibernate fluida con algunas modificaciones de

...//snip 
....Mappings(m => m.AutoMappings.Add(
        AutoMap.AssemblyOf<Account>() 
        //Use my mapping overrides here 
        .UseOverridesFromAssemblyOf<MyMappingOverride>() 
        .Conventions.Add(new MyConventions()).IgnoreBase<Entity> 
       )) 

Mi clase de anulación Mapeo se ve así:

public class MyMappingOverride : IAutoMappingOverride<MyClass> { 
     public void Override(AutoMapping<MyClass> mapping) { 
      mapping.Map(x => x.LongName).Length(765); 
     } 
} 

Esto sólo es necesario para el pequeño subconjunto de entidades con valores de texto largos. ¿Tal vez algún otro lo encuentre útil?

Cuestiones relacionadas