0

我想將一個樹形結構(存​​儲爲一個鄰接表)放到一個數據庫中,我想用Fluent NHibernate和Convention mapping來做到這一點。我有以下代碼:流利的NHibernate約定映射樹結構

[...] 

NamespaceAutomapping automapping = new NamespaceAutomapping("NHibernateTree.Model", false); //Maps the classes in the namespace NHibernateTree.Model, false meaning to not map sub-namespaces like NHibernateTree.Model.ABC 

FluentConfiguration fluentConfiguration = Fluently.Configure() 
    .Database(FluentNHibernate.Cfg.Db.PostgreSQLConfiguration.PostgreSQL82.ConnectionString(connectionString)) 
    .Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<TreeNode>(automapping) 
     //.Conventions.Add<ForeignKeyNameConvention>() 
    )); 

[...] 

ISessionFactory SessionFactory = fluentConfiguration.BuildSessionFactory(); 

using (ISession session = SessionFactory.OpenSession()) 
{ 
    TreeNode root = new TreeNode() { Value = "Root" }; 

    TreeNode childA = new TreeNode() { Parent = root, Value = "Child A" }; 
    root.Children.Add(childA); 

    TreeNode childB = new TreeNode() { Parent = root, Value = "Child B" }; 
    root.Children.Add(childB); 

    session.Save(root); 
    session.Save(childA); 
    session.Save(childB); 
} 

using (ISession session = SessionFactory.OpenSession()) 
{ 
    TreeNode root = session.Query<TreeNode>().First(tn => tn.Value == "Root"); 
    Console.WriteLine(root.ToString()); 
} 

是出評論的約定如下:

public class ForeignKeyNameConvention : ForeignKeyConvention 
{ 
    protected override String GetKeyName(Member property, Type type) 
    { 
     return String.Format("\"{0}Id\"", null == property ? type.Name : property.Name); 
    } 
} 

和類NHibernateTree.Model.TreeNode看起來是這樣的:(這是唯一的類該命名空間)現在

class TreeNode 
{ 
    public virtual int Id { get; set; } 
    public virtual TreeNode Parent { get; set; } 
    public virtual ICollection<TreeNode> Children { get; set; } 
    public virtual String Value { get; set; } 

    public TreeNode() 
    { 
     Children = new Collection<TreeNode>(); 
    } 

    public override string ToString() 
    { 
     [...] 
    } 
} 

,如果我運行此代碼,輸出爲:

Root 
    Child A 
    Child B 

和數據庫中的表看起來像這樣:

Column |   Type 
-----------+----------------------- 
id  | integer 
value  | character varying(255) 
parent_id | integer 

id | value | parent_id 
----+---------+----------- 
    1 | Root | 
    2 | Child A |   1 
    3 | Child B |   1 

到目前爲止,一切都很好。但是如果我在程序中取消註釋來增加約定,那麼會發生奇怪的事情。該程序的輸出是唯一的「根」(即NHibernate的找不到了的參考子女),以及表看起來像這樣代替:

Column |   Type 
------------+----------------------- 
id   | integer 
value  | character varying(255) 
ParentId | integer 
TreeNodeId | integer 

id | value | ParentId | TreeNodeId 
----+---------+----------+------------ 
    1 | Root |   | 
    2 | Child A |  1 | 
    3 | Child B |  1 | 

列「TreeNodeId」是所有行NULL。

很明顯,這個約定搞得一團糟。我想使用這個約定來獲得外鍵的名字很好,但我無法讓它工作。

我在SO上發現了一些帖子,其中人們解決了基本相同的問題,但與約定無關。

任何幫助表示讚賞!

回答

0

我終於找到了解決辦法: 我的公約延伸的是標準功能NHibernate類的類,它看起來像這樣:https://github.com/jagregory/fluent-nhibernate/blob/master/src/FluentNHibernate/Conventions/ForeignKeyConvention.cs

它的有趣的方法是這樣的:

public void Apply(ICollectionInstance instance) 
{ 
    var columnName = GetKeyName(null, instance.EntityType); 

    instance.Key.Column(columnName); 
} 

這使得集合ChildrenTreeNode映射通過添加一個列的集合類型(在這種情況下是相同的類)。在我的情況下,我已經有這個專欄,ParentId,但NHibernate增加了另一個名爲TreeNodeId

我對此的解決方案是跳過包含與包含類相同類型的集合的映射。這意味着NHibernate不會創建額外的列TreeNodeId。因此,我沒有擴展ForeignKeyConvention,而是複製了基類ForeignkeyConvention,並將上述方法修改爲以下方法:

public void Apply(ICollectionInstance instance) 
{ 
    if (instance.EntityType != instance.ChildType) 
    { 
     String columnName = GetKeyName(null, instance.EntityType); 

     instance.Key.Column(columnName); 
    } 
}