2011-11-05 74 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」。 –