NHibernate入门教程中,如何进行简单实体映射操作?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1472个文字,预计阅读时间需要6分钟。
NHibernate 入门示例
测试项目目录结构如下:
+ Project + src + main + java + com.example + Company.java + resources +hibernate.cfg.xml + lib + NHibernate-1.2.0.CR1-bin-net-2.0.jar
1. 下载 NHibernate(版本1.2.0.CR1),将NHibernate+\bin+net-2.0目录下的文件复制到lib目录下。
2.创建Company类,用于测试。
java
package com.example;public class Company { private Long id; private String name;
// 省略getter和setter方法}
NHibernate入门示例。测试项目目录结构如下
建立一个Company类用来测试,对应的表为TBLCOMPANY。
1. 下载NHibernate(版本1.2.0.CR1),将NHibernate \bin\net-2.0下面的文件拷贝到lib目录。
2. 为实体建立Class Library的Domain工程。为工程添加\lib\Iesi.Collections.dll文件的引用(以后用)。
3. Company类的代码如下
usingSystem;
usingIesi.Collections.Generic;
namespaceNH12.MyExample.Domain
{
#regionCompany
publicclassCompany
{
privatestring_companyID;
privatestring_companyName;
publicCompany(stringid,stringname)
{
_companyID=id;
_companyName=name;
}
publicCompany()
{
}
publicvirtualstringCompanyID
{
get{return_companyID;}
set{_companyID=value;}
}
publicvirtualstringCompanyName
{
get{return_companyName;}
set{_companyName=value;}
}
#regionoverride
publicoverrideboolEquals(objectobj)
{
if(this==obj)returntrue;
if(obj==null||obj.GetType()!=this.GetType())
returnfalse;
Companycompany=objasCompany;
returncompany!=null&&company.CompanyID==_companyID;
}
publicoverrideintGetHashCode()
{
return_companyID.GetHashCode();
}
publicoverridestringToString()
{
return_companyID;
}
#endregion
}
#endregion
} 4. 将NHibernate源代码中的nhibernate-mapping.xsd文件拷贝到Domain工程的目录下,也可以拷贝到VS 2005的系统目录,这是因为映射文件使用这个xsd进行校验、输入提示等。
为Domain工程添加Company.hbm.xml映射文件,在文件的属性->Build Action中选择Embedded Resource,文件内容如下
<?xmlversion="1.0"encoding="utf-8"?>
<hibernate-mappingxmlns="urn:nhibernate-mapping-2.2"namespace="NH12.MyExample.Domain"assembly="Domain">
<classname="Company"table="TBLCOMPANY">
<idname="CompanyID">
<columnname="COMPANY_ID"sql-type="nvarchar"length="4"not-null="true"/>
<generatorclass="assigned"/>
</id>
<propertyname="CompanyName">
<columnname="COMPANY_NAME"length="70"sql-type="nvarchar"not-null="true"/>
</property>
</class>
</hibernate-mapping> 5. 添加一个Console Application的NHTest工程。为工程添加\lib\Iesi.Collections.dll、\lib\NHibernate.dll文件的引用,添加Domain项目引用。
6. 将NHibernate源代码中的nhibernate-configuration.xsd文件拷贝到NHTest工程的目录下,也可以拷贝到VS 2005的系统目录,这是因为配置文件使用这个xsd进行校验、输入提示等。
在NHTest的App.config文件中添加如下配置:
<configSections>
<section
name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate"
/>
</configSections>
<hibernate-configurationxmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<propertyname="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<propertyname="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<propertyname="connection.connection_string">Server=localhost;initialcatalog=NH;userid=sa;password=123</property>
<propertyname="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<propertyname="use_proxy_validator">False</property>
<mappingassembly="Domain"/>
</session-factory>
</hibernate-configuration> 数据库连接字符串信息改成自己的。注意1.2版本中配置信息不再支持<add name="" value="" />方式,而改用property元素,相应的name只需要把原来name值中的nhibernate.这个前缀去掉就可以,value的方式没有发生变化。
7. 写代码测试。测试代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingNH12.MyExample.Domain;
usingNHibernate;
usingNHibernate.Cfg;
usingIesi.Collections.Generic;
namespaceNH12.MyExample.Test
{
classProgram
{
staticvoidMain(string[]args)
{
ISessionFactorysessionFactory=newConfiguration().Configure().BuildSessionFactory();
ISessionsession=null;
ITransactiontrans=null;
try
{
session=sessionFactory.OpenSession();
trans=session.BeginTransaction();
Companycompany=newCompany("1000","BenQGuruCo.,Ltd.");
session.Save(company);
Console.WriteLine("company1000hasbeencreated");
Companycompany2=newCompany("2000","testcompany2");
session.Save(company2);
Console.WriteLine("company2000hasbeencreated");
Companycompany3=session.Get<Company>("1000");
Console.WriteLine("Company:id:{0}name:{1}",company3.CompanyID,company3.CompanyName);
trans.Commit();
}
catch(Exceptione)
{
trans.Rollback();
}
finally
{
session.Close();
}
sessionFactory.Close();
Console.ReadLine();
}
}
} 现在可以运行这个最简单的映射示例,运行完之后可以在TBLCOMPANY表中查询到记录。
即使是最简单的例子,我们也可以发现一些东西。
如果你一边单步执行,一边打开SQL Server的SQL Profiler进行监控(监控的Event为Stored Procedures中的RPC:Completed),可以发现,在两个session.Save()方法以及session.Get<>()方法处,并没有产生任何跟数据库进行交互的SQL语句,而只有在trans.Commit()的时候,才会产生下面这样两条SQL:
execsp_executesqlN'INSERTINTOTBLCOMPANY(COMPANY_NAME,COMPANY_ID)VALUES(@p0,@p1)',
N'@p0nvarchar(19),@p1nvarchar(4)',
@p0=N'BenQGuruCo.,Ltd.',@p1=N'1000'
execsp_executesqlN'INSERTINTOTBLCOMPANY(COMPANY_NAME,COMPANY_ID)VALUES(@p0,@p1)',
N'@p0nvarchar(14),@p1nvarchar(4)',
@p0=N'testcompany2',@p1=N'2000' 这是因为NHibernate在同一个session内会做对象的状态管理和缓存,对对象属性的修改被缓存起来,直到事务提交的时刻才将所有数据库更新操作应用到数据库上;在session.Get()获取对象时,先从当前session的缓存中查找是否已经存在该对象,如果有,则直接取出这个对象,而不会产生一条SQL查询。所以上面的测试只有两个INSERT语句。
在上面测试的基础上,运行如下的测试代码
ISessionFactorysessionFactory=newConfiguration().Configure().BuildSessionFactory();
ISessionsession=null,session2=null;
ITransactiontrans=null;
try
{
session=sessionFactory.OpenSession();
session2=sessionFactory.OpenSession();
trans=session.BeginTransaction();
Companycompany=session.Get<Company>("2000");
company.CompanyName="MyTestCompany ...";
Companycompany2=session2.Get<Company>("2000");
session.Update(company);
trans.Commit();
}
catch(Exceptione)
{
trans.Rollback();
}
finally
{
session.Close();
session2.Close();
}
sessionFactory.Close();
Console.ReadLine(); 执行的SQL语句如下:
execsp_executesql
N'SELECTcompany0_.COMPANY_IDasCOMPANY1_0_0_,company0_.COMPANY_NAMEasCOMPANY2_0_0_
FROMTBLCOMPANYcompany0_WHEREcompany0_.COMPANY_ID=@p0',
N'@p0nvarchar(4)',@p0=N'2000'
execsp_executesql
N'SELECTcompany0_.COMPANY_IDasCOMPANY1_0_0_,company0_.COMPANY_NAMEasCOMPANY2_0_0_
FROMTBLCOMPANYcompany0_WHEREcompany0_.COMPANY_ID=@p0',
N'@p0nvarchar(4)',@p0=N'2000'
execsp_executesqlN'UPDATETBLCOMPANYSETCOMPANY_NAME=@p0WHERECOMPANY_ID=@p1',
N'@p0nvarchar(19),@p1nvarchar(4)',@p0=N'MyTestCompany ...',@p1=N'2000' 其中第1、2句分别在session.Get()和session2.Get()调用时产生,因为这是两个不同的session,并且缓存中都还没有要取的company对象。第3句是在trans.Commit()时产生的。
另外一点需要注意,NHibernate不允许修改主键值,如果有修改,在事务提交时会丢出一个异常。这个特性在使用业务上有意义的字段作为主键时可能会面临一些问题,不过从另一个方面看,就算这种情况下NH允许修改主键,因为其它对象可能已经根据这个主键值引用该对象,所以修改同样会造成问题。至少目前我接触的项目中,对象的业务主键是不允许修改的。
本文共计1472个文字,预计阅读时间需要6分钟。
NHibernate 入门示例
测试项目目录结构如下:
+ Project + src + main + java + com.example + Company.java + resources +hibernate.cfg.xml + lib + NHibernate-1.2.0.CR1-bin-net-2.0.jar
1. 下载 NHibernate(版本1.2.0.CR1),将NHibernate+\bin+net-2.0目录下的文件复制到lib目录下。
2.创建Company类,用于测试。
java
package com.example;public class Company { private Long id; private String name;
// 省略getter和setter方法}
NHibernate入门示例。测试项目目录结构如下
建立一个Company类用来测试,对应的表为TBLCOMPANY。
1. 下载NHibernate(版本1.2.0.CR1),将NHibernate \bin\net-2.0下面的文件拷贝到lib目录。
2. 为实体建立Class Library的Domain工程。为工程添加\lib\Iesi.Collections.dll文件的引用(以后用)。
3. Company类的代码如下
usingSystem;
usingIesi.Collections.Generic;
namespaceNH12.MyExample.Domain
{
#regionCompany
publicclassCompany
{
privatestring_companyID;
privatestring_companyName;
publicCompany(stringid,stringname)
{
_companyID=id;
_companyName=name;
}
publicCompany()
{
}
publicvirtualstringCompanyID
{
get{return_companyID;}
set{_companyID=value;}
}
publicvirtualstringCompanyName
{
get{return_companyName;}
set{_companyName=value;}
}
#regionoverride
publicoverrideboolEquals(objectobj)
{
if(this==obj)returntrue;
if(obj==null||obj.GetType()!=this.GetType())
returnfalse;
Companycompany=objasCompany;
returncompany!=null&&company.CompanyID==_companyID;
}
publicoverrideintGetHashCode()
{
return_companyID.GetHashCode();
}
publicoverridestringToString()
{
return_companyID;
}
#endregion
}
#endregion
} 4. 将NHibernate源代码中的nhibernate-mapping.xsd文件拷贝到Domain工程的目录下,也可以拷贝到VS 2005的系统目录,这是因为映射文件使用这个xsd进行校验、输入提示等。
为Domain工程添加Company.hbm.xml映射文件,在文件的属性->Build Action中选择Embedded Resource,文件内容如下
<?xmlversion="1.0"encoding="utf-8"?>
<hibernate-mappingxmlns="urn:nhibernate-mapping-2.2"namespace="NH12.MyExample.Domain"assembly="Domain">
<classname="Company"table="TBLCOMPANY">
<idname="CompanyID">
<columnname="COMPANY_ID"sql-type="nvarchar"length="4"not-null="true"/>
<generatorclass="assigned"/>
</id>
<propertyname="CompanyName">
<columnname="COMPANY_NAME"length="70"sql-type="nvarchar"not-null="true"/>
</property>
</class>
</hibernate-mapping> 5. 添加一个Console Application的NHTest工程。为工程添加\lib\Iesi.Collections.dll、\lib\NHibernate.dll文件的引用,添加Domain项目引用。
6. 将NHibernate源代码中的nhibernate-configuration.xsd文件拷贝到NHTest工程的目录下,也可以拷贝到VS 2005的系统目录,这是因为配置文件使用这个xsd进行校验、输入提示等。
在NHTest的App.config文件中添加如下配置:
<configSections>
<section
name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate"
/>
</configSections>
<hibernate-configurationxmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<propertyname="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<propertyname="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<propertyname="connection.connection_string">Server=localhost;initialcatalog=NH;userid=sa;password=123</property>
<propertyname="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<propertyname="use_proxy_validator">False</property>
<mappingassembly="Domain"/>
</session-factory>
</hibernate-configuration> 数据库连接字符串信息改成自己的。注意1.2版本中配置信息不再支持<add name="" value="" />方式,而改用property元素,相应的name只需要把原来name值中的nhibernate.这个前缀去掉就可以,value的方式没有发生变化。
7. 写代码测试。测试代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingNH12.MyExample.Domain;
usingNHibernate;
usingNHibernate.Cfg;
usingIesi.Collections.Generic;
namespaceNH12.MyExample.Test
{
classProgram
{
staticvoidMain(string[]args)
{
ISessionFactorysessionFactory=newConfiguration().Configure().BuildSessionFactory();
ISessionsession=null;
ITransactiontrans=null;
try
{
session=sessionFactory.OpenSession();
trans=session.BeginTransaction();
Companycompany=newCompany("1000","BenQGuruCo.,Ltd.");
session.Save(company);
Console.WriteLine("company1000hasbeencreated");
Companycompany2=newCompany("2000","testcompany2");
session.Save(company2);
Console.WriteLine("company2000hasbeencreated");
Companycompany3=session.Get<Company>("1000");
Console.WriteLine("Company:id:{0}name:{1}",company3.CompanyID,company3.CompanyName);
trans.Commit();
}
catch(Exceptione)
{
trans.Rollback();
}
finally
{
session.Close();
}
sessionFactory.Close();
Console.ReadLine();
}
}
} 现在可以运行这个最简单的映射示例,运行完之后可以在TBLCOMPANY表中查询到记录。
即使是最简单的例子,我们也可以发现一些东西。
如果你一边单步执行,一边打开SQL Server的SQL Profiler进行监控(监控的Event为Stored Procedures中的RPC:Completed),可以发现,在两个session.Save()方法以及session.Get<>()方法处,并没有产生任何跟数据库进行交互的SQL语句,而只有在trans.Commit()的时候,才会产生下面这样两条SQL:
execsp_executesqlN'INSERTINTOTBLCOMPANY(COMPANY_NAME,COMPANY_ID)VALUES(@p0,@p1)',
N'@p0nvarchar(19),@p1nvarchar(4)',
@p0=N'BenQGuruCo.,Ltd.',@p1=N'1000'
execsp_executesqlN'INSERTINTOTBLCOMPANY(COMPANY_NAME,COMPANY_ID)VALUES(@p0,@p1)',
N'@p0nvarchar(14),@p1nvarchar(4)',
@p0=N'testcompany2',@p1=N'2000' 这是因为NHibernate在同一个session内会做对象的状态管理和缓存,对对象属性的修改被缓存起来,直到事务提交的时刻才将所有数据库更新操作应用到数据库上;在session.Get()获取对象时,先从当前session的缓存中查找是否已经存在该对象,如果有,则直接取出这个对象,而不会产生一条SQL查询。所以上面的测试只有两个INSERT语句。
在上面测试的基础上,运行如下的测试代码
ISessionFactorysessionFactory=newConfiguration().Configure().BuildSessionFactory();
ISessionsession=null,session2=null;
ITransactiontrans=null;
try
{
session=sessionFactory.OpenSession();
session2=sessionFactory.OpenSession();
trans=session.BeginTransaction();
Companycompany=session.Get<Company>("2000");
company.CompanyName="MyTestCompany ...";
Companycompany2=session2.Get<Company>("2000");
session.Update(company);
trans.Commit();
}
catch(Exceptione)
{
trans.Rollback();
}
finally
{
session.Close();
session2.Close();
}
sessionFactory.Close();
Console.ReadLine(); 执行的SQL语句如下:
execsp_executesql
N'SELECTcompany0_.COMPANY_IDasCOMPANY1_0_0_,company0_.COMPANY_NAMEasCOMPANY2_0_0_
FROMTBLCOMPANYcompany0_WHEREcompany0_.COMPANY_ID=@p0',
N'@p0nvarchar(4)',@p0=N'2000'
execsp_executesql
N'SELECTcompany0_.COMPANY_IDasCOMPANY1_0_0_,company0_.COMPANY_NAMEasCOMPANY2_0_0_
FROMTBLCOMPANYcompany0_WHEREcompany0_.COMPANY_ID=@p0',
N'@p0nvarchar(4)',@p0=N'2000'
execsp_executesqlN'UPDATETBLCOMPANYSETCOMPANY_NAME=@p0WHERECOMPANY_ID=@p1',
N'@p0nvarchar(19),@p1nvarchar(4)',@p0=N'MyTestCompany ...',@p1=N'2000' 其中第1、2句分别在session.Get()和session2.Get()调用时产生,因为这是两个不同的session,并且缓存中都还没有要取的company对象。第3句是在trans.Commit()时产生的。
另外一点需要注意,NHibernate不允许修改主键值,如果有修改,在事务提交时会丢出一个异常。这个特性在使用业务上有意义的字段作为主键时可能会面临一些问题,不过从另一个方面看,就算这种情况下NH允许修改主键,因为其它对象可能已经根据这个主键值引用该对象,所以修改同样会造成问题。至少目前我接触的项目中,对象的业务主键是不允许修改的。

