NHibernate学习
1. hibernate.cfg.xml配置文件 (主要是数据库链接和关联映射文件)
<?xmlversion="1.0"encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory>
<propertyname="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<propertyname="connection.connection_string">Uid=sa;Pwd=`1234qwert;Initial Catalog=T_DZ;Data Source=10.163.100.173</property>
<propertyname="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<propertyname="show_sql">true</property>
<mappingassembly="NhibernatePro"/>
<!--关联 hbm文件的 assembly-->
</session-factory>
</hibernate-configuration>
注意:该文件的输出方式必须设置成:始终复制
2. Domain和hbm文件的声明
(1) 有两个表 Product和 Category表,表结构如下
(2) 对应的两个Domain如下:
1. Category.cs
namespace NhibernatePro.App_Code.Domain
{
[Serializable]
public class Category
{
public virtual string CategoryId { get; set; }
public virtual string CategoryName { get; set; }
public virtual IList<Product> ProductList { get; set; }
//用于一对多的关联,一个Category对应多个Product
}
}
2. Product.cs
namespace NhibernatePro.App_Code.Domain
{
[Serializable]
public class Product
{
public virtual string ProductId { get; set; }
public virtual string ProductName { get; set; }
public virtual decimal ProductProce { get; set; }
public virtual Category Category { get; set; }
//多对一的关联一个Product属于一个Category
}
}
备注: 属性必须定义成 virtual的。
(3) Hbm映射文件的定义
Hbm文件的名称必须和Domain的名称一样
Hbm文件的生成操作必须设置成嵌入的资源
Eg: Category对应的映射文件名称为: Category.hbm.xml
1. Category.hbm.xml
<?xmlversion="1.0"encoding="utf-8" ?>
<hibernate-mappingxmlns="urn:nhibernate-mapping-2.2"assembly="NhibernatePro"namespace="NhibernatePro.App_Code.Domain">
<classname="Category"table="Category">
<idcolumn="CategoryId"name="CategoryId"type="string">
<generator class="assigned">
</generator>
</id>
<propertyname="CategoryName"type="string">
<columnname="CategoryName"></column>
</property>
<bag name="ProductList" cascade="all" lazy="true" inverse="true">
<key column="CId" not-null = "false"/>
<one-to-many class="Product"></one-to-many>
</bag>
<!--一对多的配置
1. cascade 配置 可以保证在存Category时级联存Product. ,也可以在删除category时级联删除product
2. lazy=true 延迟加载,因为分类下有很多产品,所以需要设置级联,这里需要保证session没有关闭,以便在级联取数据时不会报session关闭的错误。
3. inverse=true 默认的inverse为false表示关联关系由外键表维护即Product表,true表示由主键表维护,即Category。在级联删除时必须设置为true
-->
</class>
</hibernate-mapping>
2. Product.hbm.xml
<?xmlversion="1.0"encoding="utf-8" ?>
<hibernate-mappingxmlns="urn:nhibernate-mapping-2.2"assembly="NhibernatePro"namespace="NhibernatePro.App_Code.Domain">
<classname="Product"table="Product">
<idcolumn="ProductId"name="ProductId"type="string">
<generatorclass="assigned">
</generator>
</id>
<propertyname="ProductName"type="string">
<columnname="ProductName"></column>
</property>
<propertyname="ProductProce"type="decimal">
<columnname="ProductProce"></column>
</property>
<many-to-one name="Category" column="CId" not-null="false" cascade="save-update" lazy="false"></many-to-one>
<!--
1. 多对一两边的column均为外键表中的关联外键
2. cascade="save-update" 保证在新建和保存Product时可以级联保存和更新Category
3. lazy =false 表示非延迟加载,在取product数据时就把category数据也取出来(这样可以防止session关闭后通过p.Category.CategoryName取数时报session关闭)
-->
</class>
</hibernate-mapping>
3. Hibernate 工具类,用于获取Session和关闭链接
namespace NhibernatePro.App_Code.Utility
{
classHibernateHelper
{
ISession session =null;
publicISession GetSession() {
if(null == session || !(session.IsOpen)){
Configuration config = new Configuration().Configure("hibernate.cfg.xml");
ISessionFactory sessionFactory = config.BuildSessionFactory();
session = sessionFactory.OpenSession();
}
return session;
}
public void Close(ISession session) {
if(null != session){
session.Flush();
session.Clear();
session.Close();
}
}
}
}
4. 数据访问层
(1) 通用接口
namespace NhibernatePro.App_Code.DAL
{
public interface IDAL<T>
{
void Add(T t);
T Get(string id);
void Update(T t);
void Delete(string id);
IList<T> ListAll();
IList<T> ListByPage(int currPage,int pageSize);
Int32 Count<T>();
}
}
(2) ProductDAL对IDAL的实现
namespace NhibernatePro.App_Code.DAL
{
public class ProductDAL: IDAL<Product>
{
HibernateHelper hh = new HibernateHelper();
//添加一个Product
public void Add(Product t)
{
try
{
ISession session = hh.GetSession();
ITransaction trans = session.BeginTransaction();
session.SaveOrUpdate(t);
trans.Commit();
hh.Close(session);
}
catch(Exception ex)
{
ex.StackTrace.ToString();
}
}
//获取一个Product
public Product Get(string id)
{
ISession session = hh.GetSession();
Product product = session.Get<Product>(id);
hh.Close(session);
return product;
}
//更新
public void Update(Product t)
{
}
//删除
public void Delete(string id)
{
Product p = Get(id);
ISession session = hh.GetSession();
session.Delete(p);
hh.Close(session);
}
//获取全部的Product
public IList<Product> ListAll()
{
ISession session = hh.GetSession();
IList<Product> productList = session.CreateQuery("from Product").List<Product>();
hh.Close(session);
return productList;
}
//分页获取
public IList<Product> ListByPage(int currPage, int pageSize)
{
ISession session = hh.GetSession();
IQuery query = session.CreateQuery("from Product");
//query.SetParameter(0,"value1"); //设置hql的参数,下标从0开始
query.SetFirstResult((currPage - 1)*pageSize); //分页的开始位置
query.SetMaxResults(pageSize); //一页有多少条
IList<Product> productList = query.List<Product>();
hh.Close(session);
return productList;
}
//获取总条数
public int Count<T>()
{
Int32 count = 0;
ISession session = hh.GetSession();
IQuery query = session.CreateSQLQuery("select count(*) from Product");
count = (Int32)query.UniqueResult();
return count;
}
}
}
(备注)对于有添加更新删除的操作,应该先开启事物,最后在提交
5. 业务层BLL
该层直接调用DAL层中的方法。
6. 测试
使用NUnit 进行测试
用NUnit加载项目生成的exe文件,即可看到如下的测试方法。
namespace NhibernatePro.App_Code.Test
{
[TestFixture]
class TestCase
{
[Test]
public void ListCategory()
{
CategoryBLL categoryBLL = new CategoryBLL();
IList<Category> categoryList = categoryBLL.ListAll();
if(null != categoryList)
{
foreach(Category c in categoryList)
{
Console.WriteLine(c.CategoryName);
IList<Product> productList = c.ProductList;
foreach(Product p in productList)
{
Console.WriteLine(p.ProductName + ":" + p.ProductProce);
}
Console.WriteLine();
}
}
}
[Test]
public void ListProduct()
{
ProductBLL productBLL = new ProductBLL();
IList<Product> productList = productBLL.ListAll();
if(null != productList)
{
foreach(Product p in productList)
{
Console.WriteLine("{0},{1},{2}", p.ProductName, p.ProductProce, p.Category.CategoryName);
}
}
}
[Test]
public void listByPage()
{
ProductBLL productBLL = new ProductBLL();
Int32 currPage = 1;
Int32 pageSize = 5;
IList<Product> productList = productBLL.ListByPage(currPage, pageSize);
if (null != productList)
{
foreach (Product p in productList)
{
Console.WriteLine("{0},{1},{2}", p.ProductName, p.ProductProce, p.Category.CategoryName);
}
}
}
[Test]
public void getProduct()
{
ProductBLL productBLL = new ProductBLL();
string productId = "AE93D4DF-1650-4E12-BE0A-EF698E6E1127";
Product p = productBLL.Get(productId);
if(null != p)
{
Console.WriteLine("{0},{1},{2}", p.ProductName, p.ProductProce, p.Category.CategoryName);
}
}
[Test]
//保存一个product它的category是已经存在的
public void saveProduct1()
{
CategoryBLL categoryBLL = new CategoryBLL();
string categoryId = "aed459a5-2c0a-441f-a019-2c2b389a7fcd";
Category category1 = categoryBLL.Get(categoryId);
Product p = new Product();
p.ProductId = Guid.NewGuid().ToString();
p.ProductName = "banana";
p.ProductProce = new decimal(15);
p.Category = category1;
ProductBLL productBLL = new ProductBLL();
CategoryBLL categoryBll = new CategoryBLL();
// categoryBll.Add(category1);
productBLL.Add(p);
}
//保存一个product它的category需要级联添加
[Test]
public void saveProductWithCategory()
{
Category c = new Category()
{
CategoryId = Guid.NewGuid().ToString(), CategoryName = "Water"
};
Product p = new Product()
{
ProductId = Guid.NewGuid().ToString(), ProductName = "EverGreat Ice Water", ProductProce = new decimal(500), Category = c
};
ProductBLL productBLL = new ProductBLL();
CategoryBLL categoryBll = new CategoryBLL();
productBLL.Add(p);
}
//删除一个product
[Test]
public void deleteProdcut()
{
string productId = "e0ccd2f1-dd26-4dca-bb39-ff318c297fff";
ProductBLL productBLL = new ProductBLL();
productBLL.Delete(productId);
Console.WriteLine("删除成功....");
}
//删除一个category (会级联删除该category下的product)
[Test]
public void deleteCategory()
{
string categoryId = "7fc0a318-9031-4683-bf5d-1de0c5ee4680";
CategoryBLL categoryBLL = new CategoryBLL();
categoryBLL.Delete(categoryId);
Console.WriteLine("删除Category成功..");
}
[Test]
public void countProduct()
{
ProductBLL productBLL = new ProductBLL();
Int32 pCount = productBLL.Count<Product>();
Console.WriteLine("count:" + pCount);
}
}
}
7. 项目的完整结构如下:
Ps.
有用链接:
1. http://www.cnblogs.com/GoodHelper/archive/2011/03/03/1965290.html
2. NHibernate 常见错误
http://blog.csdn.net/coolhe21cn/article/details/2065087