NHibernate 慎用IList
今天在NHibernate群讨论着ISet怎样访问的时候,引申了一个问题,为什么要用ISet而不用IList呢?IList是多么的简单且自然。
但是IList在处理重复的Item的时候也有不足,它是会插入重复的对象的,而ISet不会。因此在用IList做Mapping的时候,就有那么一点点不完美。
先看Many-To-Many的例子,我们需要一个中间表,当一个IList增加同一个对象,IList.Count显示为2,数据库中间表会有两条相同的记录。如一个Child 有多个Parnet,Parent可能也有多个Child。代测试代码如下:
1: [TestMethod]
2: public void ManyToManyTest()
3: {
4: var bf = new BurrowFramework();
5: bf.InitWorkSpace();
6:
7: var p = new Parent();
8: var c1 = new Child { Name = "child1" };
9: p.Children.Add(c1);
10: p.Children.Add(c1);
11:
12: Assert.AreEqual(2, p.Children.Count); //List 有两条记录
13:
14: bf.GetSession().SaveOrUpdate(p);
15:
16: bf.CloseWorkSpace();
17: }
查看数据库结果.如下:
select * from dbo.LearnNHibernate_Parent_ChildRelation
ParentId | ChildId |
C0DAC4FA-079B-42BC-BEDC-7251655A6B9C | 3117054E-8D1A-4C9D-93D4-7C6AFC715D65 |
C0DAC4FA-079B-42BC-BEDC-7251655A6B9C | 3117054E-8D1A-4C9D-93D4-7C6AFC715D65 |
对象的状态和数据库的状态是保持一致的,符合我对NHibernate预期。不过有什么业务有这样的需求呢?
但是NHibernate处理one-to-many的时候,对象的状态和数据库的状态就不太相符了。请看代码:
1: [TestMethod]
2: public void OneToMany()
3: {
4: var bf = new BurrowFramework();
5: bf.InitWorkSpace();
6:
7: var p = new Director() { Name = "Director" };
8: var c1 = new Student() { Name = "child1" };
9: p.Students.Add(c1);
10: p.Students.Add(c1);
11:
12: Assert.AreEqual(2, p.Students.Count); //对象中Count为2
13:
14: bf.GetSession().SaveOrUpdate(p);
15:
16: bf.CloseWorkSpace();
17:
18: }
在内存中Direcotry是有两个Student对象的。那么数据库是怎样呢?其实不需要查看数据库,因为One-To-Many中,是不需要中间表的,只需要在Student表中提供Director的外键就可以了。换句话说,通过NHibernate,重新获取Director对像的时候,是不可能恢复到Director拥有2个相同的Student的状态。如果我期望有两个相同的对象,那么只好用Many-To-Many的方法了。
总的来说,IList唯一的使用场景就是,一个对象可能拥有多个相同的子对象的时候。如果不是,还是用ISet比较方面,不需要为检查和移除重复对象付出的劳动力。不过这样的场景我真的没有见过,期望有哪位告知这样的场景。另外ISet不直接支持Linq,又不能用索引指示器(?),的确有点烦。
源代码在这里