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

Dan*_*rth 5 .net c# nhibernate fluent-nhibernate

假设我有以下两个类:

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

public class Item : Entity
{
    public virtual User Owner { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我创建了两个映射类:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这将导致Item具有列UserId和列的表OwnerId.当我KeyColumn("OwnerId")HasMany映射上使用时,它只适用于OwnerId列,但我想避免这种情况.有没有办法告诉NHibernate,使用映射创建的列ItemMap

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

Fir*_*iro 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);
}
Run Code Online (Sandbox Code Playgroud)

如果您将规则作为约定应用,那么您需要IHasManyConvention在 和 propertyname 上实现并应用相同的规则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");
    }
}
Run Code Online (Sandbox Code Playgroud)