#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 помог получить дополнительные детали, добавленные к вопросу в автономном режиме).