Многоколоночное уникальное ограничение FluentNHibernate automap через соглашение

#c# #nhibernate #fluent-nhibernate #automapping #convention

#c# #nhibernate #fluent-nhibernate #автоматическое отображение #соглашение

Вопрос:

Поддерживает ли автоматическая карта FluentNHibernate создание многоколоночного уникального ограничения с помощью соглашения?

Я могу легко создать уникальное ограничение для одного столбца:

 public void Apply(IPropertyInstance instance)
{
    if(instance.Name.ToUpper().Equals("NAME"))
        instance.Unique();
}
  

С критериями приемлемости для поиска только ReferenceEntity типов.

Теперь у меня есть объект, для которого я хочу создать уникальное ограничение на несколько столбцов. Я планировал украсить свойства объекта атрибутом, чтобы указать, что они являются частью одного и того же уникального ключа, т.Е.:

 public class Foo : Entity
{
    [Unique("name_parent")]
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }

    [Unique("name_parent")]
    public virtual Bar Parent { get; set; }
}
  

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

IProperyConvention Интерфейс позволяет указывать Unique для конкретного экземпляра (столбца), но без видимости над другими столбцами.

Обновить

Процесс публикации этого помог мне немного больше продумать, поэтому я написал это:

 var propertyInfo = ((PropertyInstance)(instance)).EntityType.GetMember(instance.Name).FirstOrDefault();

if (propertyInfo != null)
{
    var attributes = propertyInfo.GetCustomAttributes(false);

    var uniqueAttribute = attributes.OfType<UniqueAttribute>().FirstOrDefault();

    if (uniqueAttribute != null)
    {
        instance.UniqueKey(uniqueAttribute.Key);
    }
}
  

При выполнении кода он дважды попадает на instance.UniqueKey(...) строку (как и ожидалось), однако созданное ограничение (pgsql);

 ADD CONSTRAINT foo_name_key UNIQUE(name);
  

Когда я ожидал

 ADD CONSTRAINT name_parent UNIQUE(name, bar);
  

Обновление 2

При использовании Override() метода в конфигурации AutoMap я могу указать правильные уникальные ключи:

 .Override<Foo>(map => {
    map.Map(x => x.Name).UniqueKey("name_parent");
    map.Map(x => x.Description);
    map.References(x => x.Parent).UniqueKey("name_parent");
})
  

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

Ответ №1:

Когда я сделал это, я создал 2 соглашения, одно из которых было AttributePropertyConvention, а другое было IReferenceConvention. Мой атрибут выглядел следующим образом:

 public class UniqueAttribute : Attribute
{
    public UniqueAttribute(string uniqueKey)
    {
        UniqueKey = uniqueKey;
    }

    public string UniqueKey { get; set; }

    public string GetKey()
    {
        return string.Concat(UniqueKey, "Unique");
    }
}
  

Соглашение о моей собственности:

 public class UniquePropertyConvention : AttributePropertyConvention<UniqueAttribute>
{
    protected override void Apply(UniqueAttribute attribute, IPropertyInstance instance)
    {
        instance.UniqueKey(attribute.GetKey());
    }
}
  

И, наконец, соглашение о ссылках:

 public class UniqueReferenceConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        var p = instance.Property.MemberInfo;

        if (Attribute.IsDefined(p, typeof(UniqueAttribute)))
        {
            var attribute = (UniqueAttribute[])p.GetCustomAttributes(typeof(UniqueAttribute), true);
            instance.UniqueKey(attribute[0].GetKey());
        }
    }
}
  

Надеюсь, это сработает для вашего сценария.

Комментарии:

1. Спасибо за ответ. Это работает (и, по сути, это то, что у меня есть), но создает ограничение уникальности только одного столбца. Если я укажу одно и то же имя для уникального ключа для двух разных столбцов, это не включит второй столбец в ограничение.

2. Это странно, потому что у меня определенно получалось создать уникальное ограничение с 2 столбцами.

3. Извините — я пропустил ту часть, что это было IReferenceConvention, а не IPropertyConvention. Работает отлично (и имеет смысл теперь, когда я вижу бит IReferenceConvention). Спасибо 🙂

Ответ №2:

Не делайте этого …. применяйте уникальность в своем домене 😉

Комментарии:

1. Логика применяется в домене, просто кажется неполной, поскольку она применяется и в базе данных. Я обновил свой вопрос более подробной информацией. (Для придирчивых, это было отмечено как правильное, поскольку JimmyP помог получить дополнительные детали, добавленные к вопросу в автономном режиме).