假设我有以下两个类:
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
。所以,基本上,它不是重构save。 最佳答案
更新:修复错误
如果你在地图上应用规则
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
和propertyname上应用相同的规则(必须通过子类型的反射获取这些规则)更新:
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");
}
}