2011-11-05 75 views
5

指定键列假设我有以下两类:避免双重合作方案

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

这将导致有列的表ItemUserId和列OwnerId。当我在HasMany映射上使用KeyColumn("OwnerId")时,它仅适用于OwnerId列,但我想避免这种情况。有没有办法告诉NHibernate,使用由ItemMap中的映射创建的列?

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

+0

您可以将属性名称更改为用户吗?公共虚拟用户用户{get;组; }。你必须改变你的引用映射当然 –

+0

@ColeW:嗯,将属性更改为用户显然会解决这个问题,但是该属性的名称不会像现在这样好。 –

+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相同的规则和propertyname(你必须通过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"); 
    } 
} 
+0

谢谢,这看起来不错。不过,我不知道你是否确定这段代码正在工作。它看起来像无尽的递归给我:在UserMap的ctor中,你创建了一个新的UserMap实例......简单地通过'this'不是更好吗? –

+0

它的一个bug thx,已修复。其实这是一个快速拍摄;) – Firo

+0

感谢您的代码 - 我只是测试它。不幸的是,还有一个问题:它没有考虑格式化外键的惯例......你能否相应地更新你的代码?示例:我的惯例是将“Id”附加到属性名称。您的代码附加“_id”。 –