Anulación para NHibernate fluido para cadenas de texto largas nvarchar(MAX) no nvarchar (255)


Cuando se establece un valor de cadena en fluent NHibernate siempre establece los valores de la base de datos a Nvarchar(255), necesito almacenar una gran cantidad de cadenas largas que se basan en las entradas del usuario y 255 es poco práctico.

Solo añadir esto es un problema con el automapper ya que estoy usando fluent NHibernate para construir la base de datos.

Author: TheAlbear, 2010-02-26

6 answers

Al agregar esta convención, la longitud predeterminada para las propiedades de cadena será 10000. Como otros han señalado, 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);
    }
}

Se pueden agregar convenciones a una configuración de automap como esta:

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

Para más información, vea Conventions en la wiki de Fluent NHibernate.

 33
Author: Lachlan Roche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-06 11:46:06

Establecer la longitud a cualquier cosa por encima 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

 17
Author: Russell Giddings,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-26 16:34:42

Con Fluent Nhibernate Automapper, uno se da cuenta rápidamente de que el comportamiento listo para usar para las columnas varchar es menos que ideal. Primero descubre que cada propiedad string se exportó como varchar(255) y necesita hacer que una columna sea varchar (max). Pero idealmente, no tendrías que hacer de cada cadena un varchar (max), ¿verdad? Por lo que la cabeza hacia abajo ese camino bien transitado de encontrar la mejor manera de ejercer el control sobre el proceso sin romper con los diversos patrones elegantes en jugar...

Si desea que las columnas varchar de la base de datos resultante se especifiquen en longitudes diferentes, busque clases de convención para que esto suceda. Puede intentar crear condiciones específicas de nombre o, en general, utilizar algún patrón de nomenclatura que haya detectado dentro de la 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 solo un nombre. Tampoco debería tener que modificar 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 da control y proporciona ese control de una manera simple y elegante?

Sería dulce si pudieras simplemente decorar tu propiedad como lo hice para la propiedad del Cuerpo 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 pudiera funcionar, tendríamos el control sobre cada cadena de forma independiente, y podríamos especificarlo directamente en nuestra entidad.

Antes Empiezo una vorágine sobre la separación de la base de datos de la aplicación, permítanme señalar que esto no es específicamente una directiva de base de datos (hice un punto de no llamar al atributo 'Varchar'). Prefiero caracterizar esto como un aumento del Sistema.string, y en mi pequeño universo estoy feliz con eso. En pocas palabras, quiero una conveniencia!

Para hacer esto, necesitamos definir la decoración que queremos usar:

using System;
namespace MyDomain.DBDecorations
{

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

Finalmente, necesitamos usar una convención de longitud de cadena para usar decoración de la propiedad de la entidad. Esta parte puede no parecer bonito, pero hace el trabajo, y la buena noticia es que usted no tendrá que mirar de nuevo!

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);
        }
    }
}

Agregue esta convención a su configuración de automapping y ahí lo tiene-siempre que desee que se obtenga una longitud específica durante ExportSchema, ahora puede decorar la propiedad string - y solo esa propiedad-directamente en su entidad!

 6
Author: Benjamin Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-11 01:38:23

Una de las formas consistentes que encontré es:

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

En el 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; }
    }
}
 3
Author: Daniel B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-28 14:01:46

Hola me encontré con esta Pregunta, con el mismo problema. Tengo una forma un poco más segura de hacerlo, ya que no quiero que todos los campos de cadena tengan 10000 caracteres por defecto.

En primer lugar me registro nhibernate fluido con algunas anulaciones

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

Mi clase Mapping override se ve así:

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

Esto solo es necesario para un subconjunto pequeño de entidades con valores de texto largos. Tal vez algunos más encontrarán esto útil?

 2
Author: Dai Bok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-30 21:28:17

Probablemente también estés usando " NHibernate validator". Si es así, Fluent NHibernate considerará automáticamente todas las anotaciones de datos relacionadas con el validador de NHibernate, incluida la longitud de la cadena, not null, etc.

 1
Author: VahidN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-12 20:17:04