您的位置:首页 > 其它

NHibernate3.2 的一对多关联查询实例总结

2012-04-18 14:02 295 查看
根据京神的NHibernate 前10节的博客,进行实验总结。京神贴传送门:/article/6947986.html

使用的NHibernate 3.2

用到的dll为 NHibernate.DLL 和 Iesi.Collections.dll(NHibernate使用了其中的ISet 集合)
测试环境 VS2010+MYSQL5.5

测试内容:对Customer 与 Order 的关联查询



需要注意的地方:
1,hibernate.cfg.xml 文件属性 复制到输出目录 始终复制 否则出现
未处理 NHibernate.Cfg.HibernateConfigException
Message=An exception occurred during configuration of persistence layer.
Source=NHibernate
InnerException: System.IO.FileNotFoundException
Message=未能找到文件“D:\Workspace\CSharp\ReleaseWorkspace\实验基地\NHibernateTest2\bin\Debug\hibernate.cfg.xml”。
Source=mscorlib
2,mapping 文件 属性 生成操作 设置成 嵌入的资源 否则出现
未处理 NHibernate.MappingException
Message=An association from the table TB_ORDER refers to an unmapped class: NHibernateTest2.PM.Entity.Customer

3,关于hibernate.cfg.xml的内容
connection.connection_string 属性值

mysql
<property name="connection.connection_string">
Database=hellodb;Data Source=192.168.1.186;User Id=root;Password=root
</property>
sqlserver
<property name="connection.connection_string">
Data Source=.\SQLEXPRESS;Initial Catalog=NHibernateSample;Integrated Security=True;Pooling=False
</property>
integrated security=true 的意思是集成验证,也就是说使用Windows验证的方式去连接到数据库服务器。这样方式的好处是不需要在连接字符串中编写用户名和密码,从一定程度上说提高了安全性。

具体不同的数据库请参照 下载的Nhibernate 中的Configuration_Templates 文件夹下的文件,看了几个语句都不大相同,
如:把sqlserver中的: <property name="adonet.batch_size">10</property> <property name="show_sql">false</property>
写入到试用mysql中的也没问题。感觉就是一些参数设置,与数据无关的公共属性。

最后不要忘了设置 <mapping assembly="NHibernateTest2"/>

4,关于动态代理:
有三种3种IoC框架动态代理方式,分别为:Castle框架、LinFu框架、Spring.Net框架。
不过网上看到这样一段话:in NHibernate 3.2 you do not need NHibernate.ByteCode.LinFu.dll because NHibernate 3.2 implements the proxy by itself. so we need modify the config like as:
就是说,从Nhibernate3.2 开始,NHibernate本身就提供了一个动态代理,可以不再使用第三方的代理了。
<property name='proxyfactory.factory_class'>NHibernate.Bytecode.DefaultProxyFactoryFactory , NHibernate</property>

5,关于mapping文件的内容
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateTest2"
namespace="NHibernateTest2.PM.Entity">
<hibernate-mapping
schema="schemaName" (1)
default-cascade="none|save-update" (2)
auto-import="true|false" (3)
default-access="property|field|nosetter|ClassName" (4)
assembly="assembly.name" (5)
namespace="namespace.name" (6)
>
这个元素有六个可选属性。

Schema(可选) :数据表结构名称;
(1) Default-cascade(可选,默认值为none) :数据表级联类型;
(2) Auto-import(可选,默认值true) :指示出是否可以在查询语句中不指定类名;
(3) Default-access(可选,默认值为”property”):指示出NHibernate用于访问字段的策略;
(4) Assemble(可选):如果在引用实体类时没有指明类名前缀,则用此选项值作为默认的类名前缀;
(5) Namespace(可选):指示同名称空间;
如果你有两个同名的被持久化的对象(classname相同),则必须将”auto-import” 选项值设为false,否则当你访问这个对象时NHibernate会抛出一个异常。

<class name="Customer" table="TB_CUSTOMER">

<class
name="ClassName" (1)
table="tableName"(2)
discriminator-value="discriminator_value"(3)
mutable="true|false"(4)
schema="owner"(5)
proxy="ProxyInterface"(6)
dynamic-update="true|false"(7)
dynamic-insert="true|false"(8)
polymorphism="implicit|explicit"(9)
where="arbitrary sql where condition"(10)
persister="PersisterClass"(11)
lazy="true|false"(12)
/>

(1) name:持久类在.Net中的类型的的全名及其所在程序集;
(2) table:数据库中的数据表名称;
(3) discriminator-value(可选,默认值为类名):用于区分单独的子集,使用与多态形式;
(4) mutable(可选,默认值为true):指定类实例是否易变;
(5) schema(可选):重新指定hibernate-mapping中的Schema选项值;
(6) proxy(可选):指定用于实现惰性初始的接口,如果所有属性都被声明为Virtual,则可以将类名指定给此选项;
(7) dynamic-update(可选,默认值false):指示出NHibernate在运行时产生的Update SQL语句是否仅包含被修改了的字段;
(8) dynamic-insert:(可选,默认值false):指示出NHibernate在运行时产生的Insert SQL语句是否仅包含被值不为Null的字段;
(9) polymorphism(可选,默认值implict):指示出是否需要有确指明查询是否使用多态性;
(10) where(可选):指定Where SQL语句可以获取这个类类型的对象;
(11) persister(可选):指定用户自定义的IClassPersister;
(12) lazy(可选):将此项设为true等同与将它自己的类名赋予给proxy选项。

<generator class="native"></generator>
常用的类型有:
1:Assigned,主键由应用逻辑产生,数据交由hibernate保存时,主键值已经设置完毕,无需hibernate干预
2:hilo,通过hi/lo算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态
3:identity,采用数据库提供的主键生成机制,如sqlserver,mysql中的自增主键生成机制
4:sequence,采用数据库提供的sequence机制生成主键,如oralce sequence
5:native,由hibernate根据数据库适配器中的定义,自动采用identity,hilo,sequence的其中一种作为主键生成方式

注意 Version 的使用(用于并发控制)。。<version name="Version" column="CVERSION" type="integer" unsaved-value="0"/>

component 的使用
<component name="CustomerName" class="CustomerName">
<property name="FirstName" column="CFIRSTNAME" type="string"
length="32" not-null="false" unique-key="un_CustomerName"/>
<property name="LastName" column="CLASTNAME" type="string"
length="32" not-null="false" unique-key="un_CustomerName"/>
</component>
这个 unique-key 啥意思?随便改动无影响。。。

一对多关系的设置
<set name="Orders" table="TB_ORDER" generic="true" inverse="true" >
<key column="CUSTOMERID" foreign-key="TB_ORDER_FK"/>
<one-to-many class="Order"/>
</set>
这个 generic 啥意思?

<set name="Posts" table="Posts"
where="(len(Title) > 6)" order-by="ORDERDATE ASC">
<key column="BlogId"/>
<one-to-many class="Post"/>
</set>

<set
name="propertyName" (1)
table="table_name" (2)
schema="schema_name" (3)
lazy="true|false" (4)
inverse="true|false" (5)
cascade="all|none|save-update|delete|all-delete-orphan" (6)
sort="unsorted|natural|comparatorClass" (7)
order-by="column_name asc|desc" (8)
where="arbitrary sql where condition" (9)
fetch="select|join|subselect" (10)
batch-size="N" (11)
access="field|property|ClassName" (12)
optimistic-lock="true|false" (13)
outer-join="auto|true|false" (14)
>

<key .... />
<one-to-many .... />
</set>

参照 http://ayende.com/blog/3943/nhibernate-mapping-set
lazy controls whatever this collection will be lazy loaded or not. By default it is set to true.
lazy就是是否延迟加载 默认为true,大概就是 如果为true则会执行2个sql语句,第二个单独用来查询这个set,而为false则是 子类父类 一个sql搞定。
in general, it is suggested that you would not set this in the mapping 通常情况下,不建议使用该属性

inverse
let NHibernate know which side of the association is the owner of the association.
默认(false)情况下,当向子实体表插入数据时,子表中的父表ID 被设置了2次。一次insert的时候,另一次是update时候。
也就是说子表负责维护了父表的ID,这样通常是不合适的。应当是父表去维护自己的ID,因此把此属性设置成true,来告诉NHibernate
子表的父表ID 不用子表去维护。

cascade
none - do not do any cascades, let the users handles them by themselves.
save-update - when the object is saved/updated, check the associations and save/update any object that require it (including save/update the associations in many-to-many scenario).
delete - when the object is deleted, delete all the objects in the association.
delete-orphan - when the object is deleted, delete all the objects in the association. In addition to that, when an object is removed from the association and not associated with another object (orphaned), also delete it.
all - when an object is save/update/delete, check the associations and save/update/delete all the objects found.
all-delete-orphan - when an object is save/update/delete, check the associations and save/update/delete all the objects found. In additional to that, when an object is removed from the association and not associated with another object (orphaned), also delete it.

由于版本的提升 对应的类为:

using NHibernate.Collection.Generic;
namespace NHibernateTest2.PM.Entity
{
public class Customer
{
public virtual int CustomerID { get; set; }
public virtual int Version { get; set; }
public virtual CustomerName CustomerName { get; set; }

public virtual PersistentGenericSet<Order> Orders { get; set; }
}
}


6.查询代码:实现的功能是:查找用户及用户订单日期在 OrderDate 之后的订单集合

//1 --------SQL 方式
string sql = "SELECT distinct {c.*} from TB_CUSTOMER {c} ";
sql += " inner join TB_Order o on o.CustomerID = {c}.CustomerID";
sql += " where DATE(o.OrderDate) >= :orderDate";

return Session.CreateSQLQuery(sql)
.AddEntity("c", typeof(Customer))
.SetDateTime("orderDate", orderDate)
.List<Customer>();

注意 {c} 的用法
//

//2----------HQL 方式
return Session.CreateQuery("select distinct  c from Customer c inner join c.Orders o  where date(o.OrderDate) >= :orderDate")
.SetDateTime("orderDate", orderDate)
.List<Customer>();

注意Select C from 而不是传统的 From。
c.Orders 其实就是Customer的那个 集合字段。感觉好像是全部查询出来,然后再从集合中过滤一样。。??
//3----------Criteria 条件查询方式

return Session.CreateCriteria(typeof(Customer))
.CreateCriteria("Orders")
.Add(Restrictions.Ge("OrderDate", orderDate))
.SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())
.List<Customer>();

详情请见:http://www.cnblogs.com/Byrd/archive/2012/04/11/2442679.html
//3.2---------投影方式

IList<int> ids = Session.CreateCriteria(typeof(Customer))
.SetProjection(Projections.Distinct(Projections.ProjectionList()
.Add(Projections.Property("CustomerID"))
)
)
.CreateCriteria("Orders")
.Add(Restrictions.Gt("OrderDate", orderDate))
.List<int>();

return Session.CreateCriteria(typeof(Customer))
.Add(Restrictions.In("CustomerID", ids.ToArray<int>()))
.List<Customer>();


简单的测试语句:

DateTime dateTime = Convert.ToDateTime(DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd"));
IList<Customer> list = customerService.GetCustomerWithOrderLimited(dateTime);
MessageBox.Show(list.Count.ToString());
if (list.Count > 0)
{
MessageBox.Show(list[0].Orders.Count.ToString());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: