Переопределение для fluent NHibernate для длинных текстовых строк nvarchar (MAX) не nvarchar(255)

когда вы устанавливаете строковое значение в fluent NHibernate, оно alwasy устанавливает DB vales в Nvarchar (255), мне нужно хранить довольно много длинной строки, основанной на пользовательских входах, и 255 непрактично.

просто добавить это проблема с automapper, поскольку я использую fluent NHibernate для создания базы данных.

6 ответов


добавление этого соглашения установит длину по умолчанию для строковых свойств 10000. Как отмечали другие, это будет столбец 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);
    }
}

соглашения могут быть добавлены в конфигурацию automap следующим образом:

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

дополнительные сведения см. В разделе конвенций в свободно NHibernate Вики.


установка длины на что-либо более 4001 создаст NVarchar (MAX)...

.WithLengthOf(10000);

см. здесь для более подробной информации...

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


С беглым Nhibernate Automapper, быстро понимает, что поведение из коробки для столбцов varchar меньше, чем идеально. Сначала вы обнаружите, что каждое строковое свойство было экспортировано как varchar(255), и вам нужно сделать столбец varchar(max). Но в идеале вам не нужно было бы делать каждую строку varchar (max), верно? Таким образом, вы направляетесь вниз, что хорошо протоптанный путь найти лучший способ оказать контроль над процессом, не выходя из различных элегантных моделей на играть...

Если вы хотите, чтобы результирующие столбцы varchar базы данных указывались на разной длине, вы смотрите на классы соглашений, чтобы это произошло. Вы можете попробовать создать условия, зависящие от имени, или вообще использовать некоторый шаблон именования, обнаруженный внутри класса convention.

ни один из них не идеален. Перегрузка имени с целью указания предполагаемой спецификации в другой части кода неудачна - ваше имя должно быть просто именем. И не должны были. чтобы изменить код соглашения каждый раз, когда необходимо добавить или изменить свойство класса ограниченной длины. Итак, как вы можете написать класс convention, который дает вам контроль и обеспечивает этот контроль простым и элегантным способом?

было бы неплохо, если бы вы могли просто украшения ваша собственность, как я сделал для свойства тела здесь:

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

если бы это могло работать, у нас был бы контроль над каждой строкой независимо, и мы могли бы указать его непосредственно в наша сущность.

прежде чем я начну водоворот над отделением базы данных от приложения, позвольте мне указать, что это не специально директива базы данных (я сделал точку не вызывая атрибут "Varchar"). Я предпочитаю характеризовать это как увеличение системы.струна, и в моей маленькой вселенной я счастлива этим. Короче говоря, я хочу удобства!

для этого нам нужно определить украшение мы хотим использовать:

using System;
namespace MyDomain.DBDecorations
{

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

наконец, нам нужно использовать соглашение длины строки для использования украшения свойства сущности. Эта часть может показаться не очень красивой, но она делает свою работу, и хорошая новость в том, что вам не придется смотреть на нее снова!

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

добавьте это соглашение в свою конфигурацию automapping, и там у вас есть это - всякий раз, когда вы хотите получить определенную длину во время ExportSchema, теперь вы можете просто украсить строку собственность - и только эта собственность-право в вашей сущности!


один из последовательных способов, который я нашел:

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

, в котором VarcharMax и классы

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

Привет, я столкнулся с этим вопросом, с той же проблемой. У меня есть немного безопасное способ сделать это, поскольку я не хочу, чтобы все строковые поля имели 10000 символов по умолчанию.

во-первых, я регистрирую свободно nhibernate с некоторыми переопределениями

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

мой класс переопределения отображения выглядит следующим образом:

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

это требуется только для небольшого подмножества объектов с длинными текстовыми значениями. Может быть, кто-то еще найдет это полезным?


Вероятно, вы используете "NHibernate на валидатор" Как хорошо. Если да, Fluent NHibernate автоматически рассмотрит все аннотации данных, связанные с валидатором NHibernate, включая длину строки, а не null и т. д.