Подтвердить что ты не робот

Переопределить для беглого NHibernate для длинных текстовых строк nvarchar (MAX), а не nvarchar (255)

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

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

4b9b3361

Ответ 1

Добавление этого соглашения будет устанавливать длину по умолчанию для свойств строки до 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 >()))

Для получения дополнительной информации см. Conventions в вики Fluent NHibernate.

Ответ 3

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

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

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

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

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" ). Я предпочитаю характеризовать это как увеличение System.string, и в моей собственной маленькой вселенной я доволен этим. Итог, я хочу удобство!

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

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

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

Ответ 4

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

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

Ответ 5

Привет, я столкнулся с этим Вопросом, с той же проблемой. У меня есть несколько более безопасный способ сделать это, поскольку я не хочу, чтобы все строковые поля имели 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);
       }
}

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

Ответ 6

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