2009-06-03 66 views
11

因此,在一個典型的模型中,如果父母可以有多個孩子並且孩子只能有一個父母,那麼您如何管理孩子的添加。我一直在使用這種方法;處理NHibernate父子集合的最佳實踐

public class Parent 
{ 
    public Parent() 
    { 
     Children = new List<Child>(); 
    } 

    public IList<Child> Children 
    { 
     get; 
     private set; 
    } 
} 

public class Child 
{ 
    public Parent Parent 
    { 
     get; 
     set; 
    } 
} 

var child = new Child(); 
var parent = new Parent(); 
parent.Children.Add(child); 
child.Parent = parent; 

問題是,無論我想添加一個新的孩子,我一定要記得添加一個引用到孩子和家長及其有點痛的兩者。我可以在父類中添加一個AddChild方法,並使其負責添加子項 - 現在的問題是有兩種方法通過Children屬性和方法添加子項。那麼這是更好的解決方案嗎?

public class Parent 
{ 
    public Parent() 
    { 
     children = new List<Child>(); 
    } 

    private IList<Child> children 
    { 
     get; 
     private set; 
    } 

    public IEnumerable<Child> Children 
    { 
     get 
     { 
      return children; 
     } 
    } 

    public void AddChild(Child child) 
    { 
     children.Add(child); 
     child.Parent = this; 
    } 
} 

有沒有關於此方面的最佳實踐的指導,你做了什麼?

回答

2

我那樣做,只是我不爲私人列表使用屬性

private IList<Child> _children 
public IEnumerable<Child> Children 
{ 
    get 
    { 
     return children; 
    } 
} 
10

這不是一個NHibernate的問題。

您應該實施AddChild方法。這些類對它們的一致性負責,所以它們不應該公開任何不可用的東西。例如,(可變)兒童列表應該隱藏。公開IEnumerable是個好主意。

你的第二個代碼是一個很好的起點。您可能需要一些更多的方法,如RemoveChild或CoundChildren。

+0

說到第二個例子,我唯一擔心的是如何使用Linq到NHibernate。由於實際映射的屬性現在是私人的,我會假設它不會被視爲可見的。有什麼想法嗎? – Gareth 2009-06-03 11:33:42

+0

您可以在您的映射中指定NHibernte在設置值時應該使用字段而不是屬性。 (例如看一下訪問屬性)。 – 2009-06-03 12:07:13

+0

是的,我得到的是當Linq到NHibernate完成時,如果該字段是私有的,並且公共訪問只返回對原始集合的引用,那麼如何使用它。例如。 (x => x.Children.Name.Equals(「Jonnie」)) – Gareth 2009-06-03 12:54:33

5

我不喜歡這樣寫道:

public class Parent 
{ 
    private ISet<Child> _children = new HashedSet<Child>(); 

    public ReadOnlyCollection<Child> Children 
    { 
     get{ return new List(_children).AsReadOnly(); } 
    } 

    public void AddChild(Child c) 
    { 
     if(c != null && !_children.Contains (d)) 
     { 
      c.Parent = this; 
      _children.Add (c); 
     } 
    } 
} 

所以,其實,這是一個有點什麼斯特凡說爲好。我只是公開一個只讀的Children列表副本,以便您可以輕鬆遍歷父代的子代,並獲取父代所擁有的子代數。 向父項添加和刪除子項必須使用AddChild & RemoveChild成員方法完成。

-1

我不喜歡所有額外AddXXX()RemoveXXX()方法混亂我的實體接口。相反,我有一個自定義列表,當調用Add()Remove()方法時引發事件。

鏈接,然後在事件處理情況:

public class Course() 
{ 
    public Course() 
    { 
    this.Topics = new EntityList<Topic>(); 
    this.Topics.AddItem += new AddItemEventHandler<Topic>(Topic_AddItem); 
    this.Topics.RemoveItem += new RemoveItemEventHandler<Topic>(Topic_RemoveItem); 
    } 

    public EntityList<Topic> Topics { get; private set; } 

    private void Topic_AddItem(Topic item, object args) 
    { 
    // Replace with your linking code: 
    EntityLinker.Link(this).With(item, args); 
    } 

    private void Topic_RemoveItem(Topic item, object args) 
    { 
    // Replace with your unlinking code: 
    EntityLinker.Unlink(this).From(item, args); 
    } 
} 
1

我使用的是公共IEnumerable的有添加|刪除方法的方法。

但是我不喜歡它,因爲它不直觀,並且會影響類的定義。

我想知道爲什麼人們不使用CustomCollection他們重寫添加,刪除,替換功能? (就像MS代碼中無處不在)?

0

我支持這個問題的接受解決方案,但是提出的解決方案並不完整,因爲使用專用字段需要映射器中的一些額外配置。對於其他人的利益,以下是完整的解決方案:

public partial class Test 
{ 
    private readonly IList<Child> children = new List<Child>(); 
    public virtual IEnumerable<Child> Children 
    { 
     get 
     { 
      return children; 
     } 
    } 
} 

注意的是,公開曝光集合必須是虛擬的NHibernate的使用它。我也想使它成爲一個只讀字段,它在創建類時被初始化,以確保它在所有場景中都存在。這裏是關聯的映射器:

public class TestMap : ClassMap<Test> 
{ 
    ... 
    HasMany(s => s.Children).Access.CamelCaseField(); 
} 

Access屬性告訴NHibernate在將值映射到模型時使用私有字段。 Access屬性上還有其他選項,允許使用各種命名配置。

0

如果您的數據庫中有一個外鍵,並且您使用標識(SQL Server)生成主鍵,則您將要從子項到父項的反向鏈接需要需要。否則,該插入會對孩子抱怨,因爲nhibernate需要爲父ID進行一些來回處理,但它尚未完成。

我們最終做了什麼來擺脫反向鏈接:使用NHibernate HiLo生成器。 這樣,NHibernate始終擁有它需要插入父/子關係的ID。

< 3!