3

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

这可能是自动映射器的问题,不确定。仍然不理想,因为它不是通过属性装饰通用的,但目前数据模型正在反映域需求。

4

2 回答 2

4

当我这样做时,我创建了 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());
        }
    }
}

希望这适用于您的场景。

于 2011-05-12T14:16:16.460 回答
1

不要这样做....在您的域中强制执行唯一性;)

于 2011-05-13T06:24:37.620 回答