Многостолбцовое уникальное ограничение FluentNHibernate с помощью соглашения - PullRequest
3 голосов
/ 12 мая 2011

Поддерживает ли Autop 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");
})

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

Ответы [ 2 ]

4 голосов
/ 12 мая 2011

Когда я сделал это, я создал 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 голос
/ 13 мая 2011

Не делайте этого .... обеспечьте уникальность в вашем домене;)

...