С помощью Fluent Nhibernate Automapper можно быстро понять, что готовое поведение для столбцов varchar далеко не идеальное. Сначала вы обнаружите, что каждое строковое свойство было экспортировано как varchar (255), и вам нужно создать столбец, который будет varchar (max). Но в идеале вам не нужно делать каждую строку varchar (макс.), Верно? Таким образом, вы идете по этому проторенному пути, чтобы найти лучший способ контролировать процесс, не нарушая различные элегантные модели в игре ...
Если вы хотите, чтобы получающиеся столбцы 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 получалась конкретная длина, теперь вы можете просто декорировать свойство строки - и только это свойство - прямо в вашей сущности!