NHibernate集合映射中的set, list, map, bag, array

set, bag, list, map的语义
集合最重要的一点是集合的语义。Java JPA中对Set, List, Collection, Map四种集合进行了定义(Java的Collection允许bag语义),NHibernate从Hibernate移植时照搬了这些概念。但是.Net社区中这些概念比较弱,很多人对set, bag, map的说法很陌生,这也对NHibernate集合映射的使用造成一定障碍。

set
集合中的对象是唯一的,无序的,不能通过索引、key值访问,只能使用enumerator列举集合对象。
.Net没有原生的set类,所以NHibernate使用Iesi.Collections的set。
不同的set实现可能存在一些差异,因此导致set表现出来的特性不大一样,但在设计、使用上的主要原则是将set看作唯一、无序的。
Iesi.Collections中,基于System.Collections.SortedList实现的ListSet在列举集合对象时顺序跟添加到set的顺序一致,但基于System.Collections.HashTable实现的HashSet就不一致了。HashSet根据对象的GetHashCode()返回值判断对象是否相等,而ListSet则使用对象的Equals()方法进行判断,所以如果没有注意重载GetHashCode()和Equals()方法,在保证唯一性上就有问题。HybridSet是Iesi.Collections中的一个混合类型,基于System.Collections.Specialized.HybridDictionary实现,主要是出于性能的考虑,内部实现会根据集合中对象的数量,自动在ListSet和HashSet两种类型间转换。
另外Iesi.Collections中的SortedSet允许提供一个IComparer接口,这样在列举集合对象时将按照IComparer提供的方法排序。

bag:
跟set基本一样,唯一不同之处在于bag中允许重复对象。
.Net没有原生的bag类,PowerCollections中有bag实现。

list:
有序集合,可以重复,使用从0开始的整数作为索引。
.Net中的List、ArrayList、LinkedList等,ArrayList用数组实现,LinkedList用双向链表实现。

map:
无序集合,key值不可以重复,可以使用任意类型的对象作为索引。
.Net中的map类有Dictionary、SortedDictionary、HashTable、SortedList等,SortedDictionary提供了排序支持。
Java中的map有HashMap和SortedMap。

set, bag, list, map语义与System.Collections的对应关系

在System.Collections下面,IList跟list语义一致,IDictionary跟map语义一致。对于具体实现类,根据它们实现的接口来确定跟set, bag, list, map语义的对应关系。
例如上面提到SortedList现了IDictionary接口,因此是一个map实现,这使得它的名字跟语义不符。
ICollection接口对语义没有明确声明,完全由具体类的实现决定属于哪种语义。抽象类CollectionBase实现了IList、ICollection接口,因此是list语义。PowerCollections中的Bag<T>是基于ICollection实现bag语义。

集合映射中实体(Entity)跟值对象(Value Object)的区别
实体拥有独立的生命周期,拥有自己的实体标识(Entity Identifier);而值对象的生命周期完全依附于它所属的实体,没有自己的标识(Identifier)。
最基本的值类型是.Net原生的那些value types,业务中简单的值对象常见的如Money、欧美风格的姓名等。复杂的业务中实体跟值对象有时候很难区分,并且同一个概念对象在不同系统环境中也可能不一样,例如在专业的地理信息处理系统中,地址可能是实体,而对于其它系统例如ERP、人力资源管理等,地址可能是值对象。
一些简单的原则可以用于区分实体跟值对象:
1. 生命周期。值对象不能脱离它所属的实体而存在,它在实体创建时或之后被创建,跟随所属的实体一起被销毁。这个生命周期是针对业务面而言,如果用内存中对象的生命周期去理解就会有疑惑,因此结合数据库中的记录(即持久化状态的对象)来理解这个生命周期概念更直观。
2. 共享引用。值对象不能被共享引用。以地址为例,如果user A和user B都有一个地址并且是一样的,设计为值对象时地址表中会有两条记录,一条属于user A一条属于user B,设计为实体时地址表中只有一条记录,user A跟user B都通过地址对象的标识引用。应该采用哪种方案看具体的业务需要。
粗糙的设计将值对象和实体一视同仁,稍微细致一点的设计就会出现不少值对象。
NHibernate中,<set>, <bag>, <list>, <map>等与<element>、<composite-element>结合,完成值对象的集合映射;one-to-one, many-to-one, one-to-many, many-to-many的出现则意味着实体间的关联关系。
值对象的集合映射不需要cascade,因为它的生命周期原则在定义中就已经确定了,cascade只用于实体间的生命周期关联控制。
集合映射中,值对象跟实体保存在不同的表中,但值对象不需要独立的配置文件,在实体映射文件中通过<set>, <bag>, <list>, <map>已经完全描述清楚了。而实体间的one-to-one, many-to-one, one-to-many, many-to-many关联,每个实体都拥有自己的配置文件。

<set>, <bag>, <list>, <map>的使用
首先根据语义从<set>, <bag>, <list>, <map>中选择合适的映射配置节点。下表是配置节点与接口类型对应关系:

Mapping Node Interface
 <set>  Iesi.Collections.ISet
 <bag>  IList
 <list>  IList
 <map>  IDictionary

对应的集合属性必须使用接口声明,因为NHibernate返回的集合对象类型,是它内部对这些接口的实现,即NHibernate.Collection命名空间下的PersistentSet、PersistentList、PersistentBag、PersistentMap,而不是ListSet、HashTable等。按照NHibernate的规定使用这些接口的具体类,NHibernate在存取时能够自动转换处理。
.Net中没有set和bag的实现,所以NHibernate使用Iesi.Collections的set,使用IList模拟bag语义。
如果属性不希望使用这些接口,可以使用access。将field设置为接口类型,在property的get, set方法中完成类型转换,通过属性配置中的access设置,让NHibernate绕开get, set方法直接存取field。

<set name="Addresses" table="USER_ADDRESS">
    <key column="USER_ID"/>
    <element column="ADDRESS" type="String"/>
</set>
<set name="Addresses" table="USER_ADDRESS">
    <key column="USER_ID" />
    <composite-element class="Address">
        <property name="Country" column="COUNTRY" type="String" />
        <property name="Province" column="PROVINCE" type="String" />
        <property name="ZipCode" column="ZIP_CODE" type="String" />
        <property name="AddressText" column="ADDRESS_TEXT" type="String" />
    </composite-element>
</set>

上面是值对象的集合映射,如果是实体间的集合映射,可以在<set>里面使用<many-to-many>, <one-to-many>。

<bag>的用法跟<set>完全一样,它们只是在语义上有区别而已。

<list>因为是有序集合,所以必须要有一个整数型索引字段,保证数据在物理存储上的顺序,这个字段的值NHibernate自动维护。其它的跟<set>完全一样。

<list name="Addresses" table="USER_ADDRESS">
    <key column="USER_ID"/>
    <index column="ADDR_INDEX"/>
    <element column="ADDRESS" type="String"/>
</list>

<map>与<list>的区别在于,<list>的index是整型,而<map>的index可以为任意类型,所以<map>中的<index>节点可以指定type属性。有的情况下,可能通过关联使用其它实体作为index,因此NHibernate为<map>提供了另外一种index配置方式,<index-many-to-many>和<index-many-to-any>。其它配置跟<set>一样。

集合元素的顺序
<set>, <bag>, <map>数据的存储是无序的,在获取数据的时候NHibernate支持排序。排序方法有两种,sort和order-by,详细用法参考NHibernate考察系列 03 many-to-many 集合映射 http://www.cnblogs.com/RicCC/archive/2007/04/08/704557.html。
加载时的排序与list的按照顺序存储有一定差异,list可以完全保留添加到集合中的顺序,而加载时的排序都是固定的规则,因此并不是完全可替代的方案。

<idbag>
<many-to-many>和值对象的集合映射,关联表跟值对象表都没有自己的标识字段,<idbag>就是用于需要使用标识字段的情况。

转载于:https://www.cnblogs.com/eric3298/archive/2010/11/23/1885310.html

【转】NHibernate集合映射中的set, list, map, bag, array相关推荐

  1. java inverse_映射中的inverse

    映射中的inverse 首先要明确一点,inverse只存在于集合标记的元素中,Hibernate所提供的集合元素包括, ,,和. inverse属性的作用是是否将对集合的修改反应到数据库中.也就是说 ...

  2. 关于openGL加载贴图纹理映射中Unknown DIB file format问题

    关于openGL加载贴图纹理映射中Unknown DIB file format问题 今天做作业发现代码可以正常编译运行,但是生成图像时显示Unknown DIB file format,后来发现是图 ...

  3. scala的多种集合的使用(6)之映射Map的操作方法

    1.创建映射 1)创建不可变的映射 scala> val status = Map(1 -> "a",2 -> "b") status: sc ...

  4. java的集合:List、Set和Map

    虚线是接口,实线是实现类: 集合能够解决的问题:集合可以丽杰为是一种更高级的数组,可以保存多条数据 本质:java官方开发人员基于java的一些基础内容(数组等等)创建了一些接口和类,然后使用这些接口 ...

  5. 20_集合_第20天(Map、可变参数、Collections)

    今日内容介绍 1.Map接口 2.模拟斗地主洗牌发牌 01Map集合概述 A:Map集合概述: 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式 ...

  6. 【腾讯面试题】Java集合:List、Set以及Map

    Java集合:List.Set以及Map 概述 Collection接口 List:有序,可重复 ArraysList Vector LinkedList Set:无序,唯一 HashSet Link ...

  7. Java集合框架总结(5)——Map接口的使用

    Java集合框架总结(5)--Map接口的使用 Map用于保存具有映射关系的数据(key-vlaue).Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较总是返回fa ...

  8. 集合、set、list、map、所有集合基本知识使用方法总结

    1.集合的概述 集合概述:就是一个专门存放多个引用数据类型对象的容器[重点::只能存放引用数据类型] 特点:1.它可以存放多种数据类型对象2.集合的长度可变的3.支持泛型 面试题:集合和数组的对比 数 ...

  9. Java SE基础知识详解第[12]期—集合(Set、Collections、Map、集合嵌套)

    写在前面: 每一个不曾起舞的日子,都是对生命的辜负. 希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己. 以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力 ...

最新文章

  1. Python 之 Numpy (三)运算
  2. Bootice1.34版本把grub4dos0.46a写入硬盘MBR失败一个例子
  3. MySQL 中一个双引号的错位引发的血案
  4. 《软件工程概论》第四章核心内容
  5. SQL获取上个月的第一天最后一天datetime
  6. utu2440 vxWorks DM9000A驱动移植
  7. Vue双向数据绑定 ~ 非常详细哦
  8. android根据ip获取查询省份,通过IP地址获取省份城市位置信息
  9. win7蓝屏0x000000f4修复_Win 7电脑突发蓝屏现象,应如何解决或避免
  10. rk3288 linux 编译,RK3288系统编译及环境搭建
  11. 宅家神器—epub阅读器
  12. 1-2 二十四点 (20 分)【Csp认证真题】
  13. 论文邮箱不是导师的_你的论文为何在导师那里“石沉大海”?
  14. 当SWOOLE遇上PROTOCOL
  15. 第二章:Djgo后台管理
  16. js - 内存溢出与内存泄漏
  17. 车牌识别,移植到android系统
  18. jQuery的change()事件
  19. 什么是公网?什么是专网?
  20. LaTex:有关LaTex的入门、语法使用

热门文章

  1. 结构化思维:掌握这3点,分析报告不再愁
  2. 天生对数字不敏感的人,如何提升对数据的敏感度?
  3. Java连接程序数据源
  4. php的email函数发送失败,php中mail函数发送邮件失败的解决方法_php技巧
  5. vue3 src/main.js文件配置
  6. 标准h5的定位_不但亲民还安全 红旗H5车门/防撞梁拆解
  7. 操作系统 第二章 进程管理
  8. 最短Hamilton路径(位运算基本思路)
  9. Tomcat启动乱码及IDEA中tomcat信息乱码解决方法
  10. 第 20 次 CSP认证 202009-5 密信与计数