热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

set,bag,list,map的语义集合最重要的一点是集合的语义。JavaJPA中对Set,List,Collection,Map四种集合进行了定义(Java的Collectio
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是基于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中,, , , 等与结合,完成值对象的集合映射;one-to-one, many-to-one, one-to-many, many-to-many的出现则意味着实体间的关联关系。
值对象的集合映射不需要cascade,因为它的生命周期原则在定义中就已经确定了,cascade只用于实体间的生命周期关联控制。
集合映射中,值对象跟实体保存在不同的表中,但值对象不需要独立的配置文件,在实体映射文件中通过, , , 已经完全描述清楚了。而实体间的one-to-one, many-to-one, one-to-many, many-to-many关联,每个实体都拥有自己的配置文件。

, , , 的使用
首先根据语义从, , , 中选择合适的映射配置节点。下表是配置节点与接口类型对应关系:
Mapping Node Interface
   Iesi.Collections.ISet
   IList
   IList
   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>
上面是值对象的集合映射,如果是实体间的集合映射,可以在里面使用,

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

因为是有序集合,所以必须要有一个整数型索引字段,保证数据在物理存储上的顺序,这个字段的值NHibernate自动维护。其它的跟完全一样。
<list name="Addresses" table="USER_ADDRESS">
    
<key column="USER_ID"/>
    
<index column="ADDR_INDEX"/>
    
<element column="ADDRESS" type="String"/>
list>

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

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


和值对象的集合映射,关联表跟值对象表都没有自己的标识字段,就是用于需要使用标识字段的情况。
推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因
    本文介绍了解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因。其中包括修改包名、解决service name重复、处理jar包冲突和添加maven依赖等解决方案。同时推荐了一个人工智能学习网站,该网站内容通俗易懂,风趣幽默,值得一看。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
author-avatar
我的老公是个兵
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有