避免在双链接方案中指定键列

时间:2011-11-05 19:15:18

标签: c# .net nhibernate fluent-nhibernate

假设我有以下两个类:

public class User : Entity
{
    public virtual IList<Item> Items { get; set; }
}

public class Item : Entity
{
    public virtual User Owner { get; set; }
}

我创建了两个映射类:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Id(x => x.Id);
        HasMany(x => x.Items);
    }
}

public class ItemMap : ClassMap<Item>
{
    public ItemMap()
    {
        Id(x => x.Id);
        References(x => x.Owner);
    }
}

这将生成一个包含Item列和UserId列的表OwnerId。当我在KeyColumn("OwnerId")映射上使用HasMany时,它仅适用于OwnerId列,但我希望避免这种情况。有没有办法告诉NHibernate,使用ItemMap中的映射创建的列?

为什么我要避免明确指定列:
根据属性的名称和一些规则自动生成列名OwnerId。如果我更改规则或属性名称,我还需要记住更改KeyColumn。所以,基本上,它不是重构保存。

1 个答案:

答案 0 :(得分:2)

更新:已修复错误

如果您在地图中应用规则,那么

public static void KeyColumnFromReference<TChild>(
    this OneToManyPart<TChild> collectionmap, ClassMap<TChild> map, Expression<Func<TChild, object>> referenceprop)
{
    string propertyname = GetPropertyName(referenceprop);
    var column = ((IMappingProvider)map).GetClassMapping()
        .References.First(m => m.Name == propertyname)
        .Columns.First().Name;

    collectionmap.KeyColumn(column);
}

public static void KeyColumnFromReference<T, TChild>(
    this OneToManyPart<TChild> collectionmap, ClassMap<TChild> map)
{
    var column = ((IMappingProvider)map).GetClassMapping()
        .References.First(m => m.Type == typeof(TChild))
        .Columns.First().Name;

    collectionmap.KeyColumn(column);
}

public UserMap()
{
    HasMany(x => x.Items)
        .KeyColumnFromReference<User, Item>(new ItemMap());

    // or

    HasMany(x => x.Items)
        .KeyColumnFromReference(new ItemMap(), u => u.Owner);
}

如果您将规则应用为约定,那么您需要实现IHasManyConvention并对EntityType和属性名(您必须通过ChildType反射获得)应用相同的规则

更新

class ForeignKeyConvention : IHasManyConvention
{
    public void Apply(IOneToManyCollectionInstance instance)
    {
        // to force the compiler to take the Name property and not the Name method
        string propertyName = ((ICollectionInspector)instance).Name;

        // should be equal to the convention for the reference key column
        instance.Key.Column(propertyName + instance.EntityType.Name + "id");
    }
}