【翻译】首只因NHibernate的应用程序

首独依据NHibernate的应用程序

 Your first NHibernate based application

英文原文地址:http://www.nhforge.org/wikis/howtonh/your-first-nhibernate-based-application.aspx

翻译原文地址:http://www.cnblogs.com/13yan/p/5671072.html

 

正文涉及到之DEMO下载

 

概念领域模型

 

让我们开始通过定义一个非常简单的天地模型。目前她是由一个名叫产品的实体。该产品有所
3 个属性:名称、 类别和间断。

 

增长一个文件夹 Domain 到你的化解方案的 FirstSample
项目。到这文件夹着补充加一个新类
Product.cs。该代码是非常简单,使用机动属性 (C# 3.0新的特性)

 

namespace FirstSolution.Domain

{

 public class Product

 {

  public string Name { get; set; }

  public string Category { get; set; }

  public bool Discontinued { get; set; }

 }

}

 

现我们怀念如果能够持久化相关数据库中之实体的实例。我们选取了
NHibernate来完成就等同任务。

领域模型中实体的一个实例对诺数据库表中的实施。所以我们不能不以数据库被定义实体和呼应的表内的照。此映射可以是另外定义一个投文件
(一个xml 文档)
或饰的实体和性质,可以好此映射。随后,我用起来映射文件的定义。

 

翻译的讲话:装饰的实业是呀?目前咱们清楚除了xml文件映射,还有Fluent
NHibernate的Mapping和特色(attribute,类似Java中注解@),装饰可能是赖他们的统称吧。

 

概念映射

 

创办一个文本夹 Mappings 到 FirstSample
项目遭到。并在该文件夹着上加一个初的 xml 文档并取名也 Product.hbm.xml。请留意”hbm”是文件名称的一样部分。这是一律项约定,这个约定用于NHibernate
自动识别这个文件呢一个炫耀文件。右键此 xml
文本点击属性,在扭转操作一起定义”嵌入的资源”

 

以 Windows 资源管理器中找到 nhibernate mapping.xsd,它在 NHibernate 的
src 文件夹着,并拿其复制到公的 SharedLibs 文件夹着。编辑 xml
映射文件时,在VS菜单中的XML-架构中导入此xsd文档。VS
然后用智能感知与说明。

 

返在 VS 将架设添加到 Product.hbm.xml
文件

 

于咱们由今天开头。每个映射文件还必定义一个 <hibernate-mapping>
根节点。

 

<?xml version=”1.0″ encoding=”utf-8″ ?>

<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.2″

       assembly=”FirstSolution”

       namespace=”FirstSolution.Domain”>

  <!– more mapping info here –>

</hibernate-mapping>

 

于炫耀文件引用领域模型类时您肯定要供的近乎的全限定的名号(如 FirstSample.Domain.Product
, FirstSample)。若一旦要 xml
不那么繁琐,你可以定义程序集名称以及天地模型类的命名空间,到清节点的一定量单特性:assembly
和namespace。它是类似于采用 C# 中的扬言。

 

而今,我们要事先乎产品实业定义一个主键。技术达到我们得以拿产品的名属性作为主键,因为此属性必须定义,并且要是绝无仅有的。但普通会用代理键代替它化主键。因此我们将增长一个名叫吧Id的特性到我们的实业。我们采用
Guid 作为 Id 的门类,但为堪是 int 或 long。

 

using System;

 

namespace FirstSolution.Domain

{

 public class Product

 {

  public Guid Id { get; set; }

  public string Name { get; set; }

  public string Category { get; set; }

  public bool Discontinued { get; set; }

 }

}

 

整的映照文件

 

<?xml version=”1.0″ encoding=”utf-8″ ?>

<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.2″

       assembly=”FirstSolution”

       namespace=”FirstSolution.Domain”>

  <class name=”Product”>

 <id name=”Id”>

   <generator class=”guid” />

 </id>

 <property name=”Name” />

 <property name=”Category” />

 <property name=”Discontinued” />

  </class>

</hibernate-mapping>

 

NHibernate
不会见以我们的主意,比如,它定义了许多合理之默认值。所以,如果你不显式地提供性的列名,它用按属性名去对应列名。或
NHibernate从类的定义着,可以自行测算的表名或列名。因此自之 xml
映射文件不见面给堆放满冗余信息。有关于映射文件再次详实的说明请参见在线文档。你可以在这里找到它。

 

而解决方案资源管理器现在应该看起像这么 (Domain.cd
包含我们简要的世界模型类图)

 

翻译的话语:

图片 1

 

配置 NHibernate

 

咱俩今天必报 NHibernate
我们怀念如果使谁数据库产品,并提供详实的链接信息,以连续字符串的花样。NHibernate
支持多数据库产品 !

 

望 FirstSolution 项目受到补充加一个新的 xml 文件,并取名为 hibernate.cfg.xml。将该性能”复制到输出目录”设置也”始终复制”。由于我们引用了SQL
Server Compact Edition数据库在first sample项目受到,所以输入以下信息及xml
文件被。

 

<?xml version=”1.0″ encoding=”utf-8″ ?>

<hibernate-configuration xmlns=”urn:nhibernate-configuration-2.2″>

  <session-factory>

 <property
name=”connection.provider”>NHibernate.Connection.DriverConnectionProvider</property>

 <property
name=”dialect”>NHibernate.Dialect.MsSqlCeDialect</property>

 <property
name=”connection.driver_class”>NHibernate.Driver.SqlServerCeDriver</property>

 <property name=”connection.connection_string”>Data
Source=FirstSample.sdf</property>

 

 <property name=”show_sql”>true</property>

  </session-factory>

</hibernate-configuration>

 

采取是安排文件,我们报告 NHibernate 我们怀念如果使用 MS SQL Server Compact
Edition作为咱们的目标数据库与数据库的号是 FirstSample.sdf (=
连接字符串)。我们还要也定义了望看到NHibernate生成并发送到数据库的
SQL语句
(在付出进程遭到调剂时强烈推荐启用这个概念)。仔细检查你的代码中生没有发生错别字

 

加上一个给FirstSample.sdf的亏欠的数据库,到 FirstSample 项目
(选择当地数据库作为模板)

 

单击添加并忽略数据集创建为导 (就是点击取消)。

 

翻译的口舌:我们不自然安装了MS SQL Server
Compact
Edition数据库,我用于Demo中拿她替换成SQLite和呼应的配备,这样咱们尽管未待以这便捷入帮派而错过特别找一个数据库了。

 

测试设置

 

大凡上来测试我们的装了。首先验证您的 SharedLibs 文件夹着生以下文件

 

乃可找到Microsoft SQL Server Compact Edition在你的主次文件夹着目录最后
8 单文本。

 

注︰ System.Data.SqlServerCe.dll
位于子文件夹着之桌面。

 

抱有其他文件可以以NHibernate 文件夹着找到。

 

以公的测试项目中添加对 FirstSample 项目之援。另外测试项目引用
NHibernate.dll、 nunit.framework.dll
和 Systm.Data.SqlServerCe.dll
(记得要引用位于 SharedLibs 文件夹着的文书
!)。要留意啊安属性”复制本地”为 true 为 System.Data.SqlServerCe.dll,
因为以默认情况下其装为 false !

 

翻译的言辞:现在VS2012之上都起自带的单元测试项目,也特别好用。所以不必引用nunit.framework.dll,同样System.Data.SqlServerCe.dll也得替换成System.Data.Sqlite.dll。

 

当测试项目中添加一个像样,命名也 GenerateSchema_Fixture。

 

本以下的代码添加到 GenerateSchema_Fixture 文件

 

using FirstSolution.Domain;

using NHibernate.Cfg;

using NHibernate.Tool.hbm2ddl;

using NUnit.Framework;



namespace FirstSolution.Tests

{

 [TestFixture]

 public class GenerateSchema_Fixture

 {

  [Test]

  public void Can_generate_schema()

  {

   var cfg = new Configuration();

   cfg.Configure();

   cfg.AddAssembly(typeof (Product).Assembly);

   

   new SchemaExport(cfg).Execute(false, true, false, false);

  }

 }

}

 

测试方法的首先执创建 NHibernate 配置类的一个新实例。此类用于配置
NHibernate。在次行,我们报告 NHibernate 配置本身。NHibernate
将注意配置信息,因为咱们从来不当测试方法中提供其他信息。所以 NHibernate
将搜输出目录中之 hibernate.cfg.xml
文件来调用。这正是我们怎么而以这个文件被这样设置的原故。

 

以第三尽的代码,我们告诉 NHibernate
它可以窥见并含Product类的次第集的投射信息。它将于坐的资源中单独找到一个(Product.hbm.xml))这样的公文。

 

季实施代码用NHibernate中 SchemaExport
的家伙类,为我们当自动生成数据库被的架构。

 

注︰ 我们先不用去解这测试方法中NHibernate 如何工作 ,
但应当关心是否是地安装。

 

若是你发出安的 TestDriven.Net
你可今天不过是右键点击里面的测试方法并精选”运行 Test(s)”来实行测试。

 

翻译的语:VS2012以上版本的单元测试可以毫无TestDriven.Net和NUnit,微软出自带的。

 

设各级一样件事是好的您应当看到下面的结果,在输出窗口

 

翻译的口舌:

图片 2

 

一旦你闹安 ReSharper
你得开始测试通过单击黄色绿色周的左手框,选择运行。

 

其二结果是,如下所示

 

翻译的讲话:原文没图,我们或用VS自带的吧,如下图

图片 3

 

于产出问题时

 

假如您测试失败,请密切检查你的目标目录,在里面找到下列文件 (即︰
m:dev\projects\FirstSolution\src\FirstSolution.Tests\bin\debug)

 

周密检查NHibernate 配置文件 (hibernate.cfg.xml))
中还是于投文件 (Product.hbm.xml)%E3%80%82)中是否生错别字,最后检查映射文件
(Product.hbm.xml))是否设置也”嵌入的资源”的”生成操作”。如果测试成功,才持续。

 

俺们先是次于的 CRUD 操作

 

今颇强烈我们的网就是准备好开端了。我们成功地实现了咱的小圈子模型,定义映射文件及部署
NHibernate。最后我们运用 NHibernate 从咱的天地模型 (和我们映射文件)
自动生成数据库架构。

 

在 DDD (参考Eric Evans的《领域让设计》) 的饱满,我们啊具的 crud
操作(创建、 读取、
更新和去)定义了Repository。Repository接口是小圈子模型不兑现的如出一辙局部!执行是一定的底蕴设备。我们如果保全我们的领域模型与持久化无关
(PI)。

 

翻译的言辞:这无异于段子我莫懂得该怎么去翻译它,但自己可讲其的意。它的横意思是根据DDD的盘算,领域模型Domain里面未应当有和持久化有关的物,比如我们的Product中无拖欠包含数据库CRUD操作,而这些CRUD的基本功操作该于储存Repository接口中贯彻。

 

暨我们的 FirstSolution 项目之Domain文件夹着补充加一个初的接口。把它们称作
IProductRepository。让我们定义以下接口

 

using System;

using System.Collections.Generic;



namespace FirstSolution.Domain

{

 public interface IProductRepository

 {

  void Add(Product product);

  void Update(Product product);

  void Remove(Product product);

  Product GetById(Guid productId);

  Product GetByName(string name);

  ICollection<Product> GetByCategory(string category);

 }

}

 

增长一个类 ProductRepository_Fixture 到测试项目下,并丰富下面的代码

 

[TestFixture]

 public class ProductRepository_Fixture

 {

  private ISessionFactory _sessionFactory;

  private Configuration _configuration;



  [TestFixtureSetUp]

  public void TestFixtureSetUp()

  {

   _configuration = new Configuration();

   _configuration.Configure();

   _configuration.AddAssembly(typeof (Product).Assembly);

   _sessionFactory = _configuration.BuildSessionFactory();

  }

 }

 

在 TestFixtureSetUp 方法的季履,我们创建一个session
factory。这是一个开销很非常的历程,因此程序运行期间应该就实行同一糟。这便是为什么将其内置这种测试中只有实行同一潮的艺术的故。

 

万一保障我们测试方法无副作用,每个测试方法执行前,我们重新创设我们的数据库架构。因此我们抬高下面的法子

 

[SetUp]

  public void SetupContext()

  {

   new SchemaExport(_configuration).Execute(false, true, false, false);

  }

 

翻译的言辞:NHibernate3.0中,只出3个参数。new
SchemaExport(cfg).Execute(false,true,false);

 

今天我们得实现向数据库被上加一个初的Product实例的测试方法。添加一个新的文件夹名为Repositories到
FirstSolution 项目。到这文件夹下加加一个类 ProductRepository。使
ProductRepository 实现 IProductRepository 接口。

 

using System;
using System.Collections.Generic;
using FirstSolution.Domain;

namespace FirstSolution.Repositories
{
 public class ProductRepository : IProductRepository
 {
  public void Add(Product product)
  {
   throw new NotImplementedException();
  }

  public void Update(Product product)
  {
   throw new NotImplementedException();
  }

  public void Remove(Product product)
  {
   throw new NotImplementedException();
  }

  public Product GetById(Guid productId)
  {
   throw new NotImplementedException();
  }

  public Product GetByName(string name)
  {
   throw new NotImplementedException();
  }

  public ICollection<Product> GetByCategory(string category)
  {
   throw new NotImplementedException();
  }
 }
}

 

操作数据

 

当今赶回ProductRepository_Fixture测试类与促成率先只测试方法

  [Test]

  public void Can_add_new_product()

  {

   var product = new Product {Name = “Apple”, Category = “Fruits”};

   IProductRepository repository = new ProductRepository();

   repository.Add(product);

  }

 

首不良运行的测试方法将败,因为咱们的贮存类非实现 Add
方法。让咱贯彻它。但是,等五星级,我们得首先定义一个聊的Helper类提供我们NHibernate
session对象及之需求。

 

using FirstSolution.Domain;
using NHibernate;
using NHibernate.Cfg; 

namespace FirstSolution.Repositories
{
 public class NHibernateHelper
 {
  private static ISessionFactory _sessionFactory; 

  private static ISessionFactory SessionFactory
  {
   get
   {
    if(_sessionFactory == null)
    {
     var configuration = new Configuration();
     configuration.Configure();
     configuration.AddAssembly(typeof(Product).Assembly);
     _sessionFactory = configuration.BuildSessionFactory();
    }
    return _sessionFactory;
   }
  } 
  public static ISession OpenSession()
  {
   return SessionFactory.OpenSession();
  }
 }
}

运作期间,不管客户端何时要一个初的session,此类只开创session
factory第一次于。

 

当今咱们得以定义 Add 方法在 ProductRepository 中,如下所示

 

public void Add(Product product)

  {

   using (ISession session = NHibernateHelper.OpenSession())

    using (ITransaction transaction = session.BeginTransaction())

    {

     session.Save(product);

     transaction.Commit();

    }

  }

 

次次运行的测试方法会更失败并显示以下信息

 

翻译的话语:

图片 4

 

当即是以 NHibernate
是默认情况下安排为以延缓加载的有着实体。这是引进的法门,我强烈建议不要转移,为了最酷之油滑。

 

俺们怎样才能解决者题材?很爱,让世界模型中有着属于性 (方法)
加上Virtual关键字即可。让咱们吧我们的Product类加上这。

 

public class Product

 {

  public virtual Guid Id { get; set; }

  public virtual string Name { get; set; }

  public virtual string Category { get; set; }

  public virtual bool Discontinued { get; set; }

 }

 

兹重新运行测试。它应有会中标,我们赢得以下输出

 

翻译的讲话:

图片 5

 

请注意NHibernate输出的 sql 语句。

 

今日我们曾成地为数据库插入一个初的Product。但被咱测试其是不是确实是这么。让咱们来扩张我们的测试方法

 

[Test]

  public void Can_add_new_product()

  {

   var product = new Product {Name = "Apple", Category = "Fruits"};

   IProductRepository repository = new ProductRepository();

   repository.Add(product);



   // use session to try to load the product

   using(ISession session = _sessionFactory.OpenSession())
   {
    var fromDb = session.Get<Product>(product.Id);
    // Test that the product was successfully inserted
    Assert.IsNotNull(fromDb);
    Assert.AreNotSame(product, fromDb);
    Assert.AreEqual(product.Name, fromDb.Name);
    Assert.AreEqual(product.Category, fromDb.Category);
   }
  }

再度运行测试。希望它们会中标……

 

而今我们准备吗落实repository中的其它方式。为了测试就我们宁可要一个repository
 (即数据库表) 已经包含了部分出品。没有呀比就重简短。只是添加
CreateInitialData 方法,如下所示添加到测试类

 

private readonly Product[] _products = new[]
     {
      new Product {Name = "Melon", Category = "Fruits"},
      new Product {Name = "Pear", Category = "Fruits"},
      new Product {Name = "Milk", Category = "Beverages"},
      new Product {Name = "Coca Cola", Category = "Beverages"},
      new Product {Name = "Pepsi Cola", Category = "Beverages"},
     };

  private void CreateInitialData()
  {
   using(ISession session = _sessionFactory.OpenSession())
    using(ITransaction transaction = session.BeginTransaction())
    {
     foreach (var product in _products)
      session.Save(product);
     transaction.Commit();
    }
  }

(在创建架构调用后) 从 SetupContext
方法调用此方法。现在历次数据库架构创建数据库后填充一些产品。

于我们测试用脚的代码库的创新方法

 

[Test]
  public void Can_update_existing_product()
  {
   var product = _products[0];
   product.Name = "Yellow Pear";
   IProductRepository repository = new ProductRepository();
   repository.Update(product); 

   // use session to try to load the product
   using (ISession session = _sessionFactory.OpenSession())
   {
    var fromDb = session.Get<Product>(product.Id);
    Assert.AreEqual(product.Name, fromDb.Name);
   }
  }

首先破运行时这个代码用失败,因为Update方法无在Repository中落实。注︰
这是意料的行为,因为以 TDD 第一潮运行测试时它当总是败 !

 

翻译的讲话:这首快速开之入门教程水来接触非常,又是DDD,又是TDD,吓够呛人矣,没接触了之总人口得以忽略。同时为足见NHibernate更多是面向有知名的面向对象程序员,可难过的凡广大程序员未可帮派时就接触到了它。叹息!

 

接近于 Add 方法我们贯彻Repository中的 Update
方法。唯一的区别是咱们调用NHibernate session对象的update
方法而不是Save方法。

 

  public void Update(Product product)

  {

   using (ISession session = NHibernateHelper.OpenSession())

   using (ITransaction transaction = session.BeginTransaction())

   {

    session.Update(product);

    transaction.Commit();

   }

  }

 

双重运行测试希望其成功。

 

Delete 方法是直了当。测试是否真正都抹记录时,我们仅是预言由会话的
get 方法返回的价是当 null。这里是测试方法

 

    [Test]

  public void Can_remove_existing_product()

  {

   var product = _products[0];

   IProductRepository repository = new ProductRepository();

   repository.Remove(product);

 

   using (ISession session = _sessionFactory.OpenSession())

   {

    var fromDb = session.Get<Product>(product.Id);

    Assert.IsNull(fromDb);

   }

  }

 

Repository中删去方法的贯彻

 

  public void Remove(Product product)

  {

   using (ISession session = NHibernateHelper.OpenSession())

    using (ITransaction transaction = session.BeginTransaction())

    {

     session.Delete(product);

     transaction.Commit();

    }

  }

 

查询数据库

 

我们仍要履行查询的数据库对象的老三单措施。我们先从太爱的一个,GetById。我们第一编写测试

 

[Test]

  public void Can_get_existing_product_by_id()

  {

   IProductRepository repository = new ProductRepository();

   var fromDb = repository.GetById(_products[1].Id);

   Assert.IsNotNull(fromDb);

   Assert.AreNotSame(_products[1], fromDb);

   Assert.AreEqual(_products[1].Name, fromDb.Name);

  }

 

然后就测试的代码

 

  public Product GetById(Guid productId)

  {

   using (ISession session = NHibernateHelper.OpenSession())

    return session.Get<Product>(productId);

  }

 

而今,那要命粗略。为以下简单栽方式,我们采用session对象的初方式。让咱开用
GetByName 方法。像过去一律我们事先勾勒测试

 

    [Test]

  public void Can_get_existing_product_by_name()

  {

   IProductRepository repository = new ProductRepository();

   var fromDb = repository.GetByName(_products[1].Name);

 

   Assert.IsNotNull(fromDb);

   Assert.AreNotSame(_products[1], fromDb);

   Assert.AreEqual(_products[1].Id, fromDb.Id);

  }

 

GetByName 方法的实现好透过使用简单只不同之道。第一使 HQL (Hibernate
Query Language) 和次独 HCQ (Hibernate Criteria
Query)。让咱们初步应用 HQL。HQL 是面向对象的查询语言 SQL 类似
(但未是等)。

 

翻译的语句:他拄的首先种植方式HQL是以此样子的。

图片 6

 

于方的以身作则中我介绍了常用的技巧使用 NHibernate
时。它深受称fluent接口。作为结果的代码是简约也重新易掌握。你得看出一个
HQL 查询是一个字符串,它可以具备嵌入 (命名) 参数。参数使用前缀
‘:’。NHibernate 定义很多之helper方法 (如示例中采取
SetString),将各种类型的价值分配为这些参数。最后经过使用 UniqueResult
我报告 NHibernate 希望只来一样久记下返回。如果多只然后引发那个,HQL
查询将回到一长长的记下。要拿走更多之音 HQL 请阅读在线文档。

 

次只本子用criteria query来寻找请求的Product。

 

  public Product GetByName(string name)

  {

   using (ISession session = NHibernateHelper.OpenSession())

   {

    Product product = session

     .CreateCriteria(typeof(Product))

     .Add(Restrictions.Eq(“Name”, name))

     .UniqueResult<Product>();

    return product;

   }

  }

 

NHibernate
的博用户认为这种做法是再多面向的靶子。在单编写的criteria语法复杂查询好高速成为麻烦知晓。

 

心想事成的最后一个计是
GetByCategory。此道返回Product的列表。测试好实现,如下所示

 

[Test]

  public void Can_get_existing_products_by_category()

  {

   IProductRepository repository = new ProductRepository();

   var fromDb = repository.GetByCategory(“Fruits”);

 

   Assert.AreEqual(2, fromDb.Count);

   Assert.IsTrue(IsInCollection(_products[0], fromDb));

   Assert.IsTrue(IsInCollection(_products[1], fromDb));

  }

 

  private bool IsInCollection(Product product,
ICollection<Product> fromDb)

  {

   foreach (var item in fromDb)

    if (product.Id == item.Id)

     return true;

   return false;

  }

 

术本身可能含有下面的代码

 

  public ICollection<Product> GetByCategory(string category)

  {

   using (ISession session = NHibernateHelper.OpenSession())

   {

    var products = session

     .CreateCriteria(typeof(Product))

     .Add(Restrictions.Eq(“Category”, category))

     .List<Product>();

    return products;

   }

  }

 

摘要

 

于即时篇文章被我早已给你哪落实基本示例领域模型,定义映射到数据库暨哪布置
NHibernate
能够持久化领域对象在数据库中。我让你显得了争通常编写和测试你的圈子对象的
CRUD 方法。我拿MS SQL Compact Edition
作为示范数据库,但足采取任何其它被支持的数额库 (你唯有待相应地重新改
hibernate.cfg.xml
文件)。我们没因让外部框架或工具外的数据库和 NHibernate 本身
(.NET 当然从不曾测算在内)。

 

翻译的讲话:终于翻译了了,这篇快速开非常适合初大方,因为提供的例证是足以给实现之,而且可以而且入门DDD和TDD,看得出作者非常用心。而自呢当其间在了批注和补充了形不了的图。

 

图片 7

 

相关文章