NHibernate-クイックガイド

この章では、NHibernateとは何か、実装できるすべてのプラットフォーム、その利点、およびそれに関連するその他の側面について説明します。

NHibernateとは何ですか?

NHibernateは、.NETFramework用の成熟したオープンソースのオブジェクトリレーショナルマッパーです。それは積極的に開発され、完全に機能し、何千もの成功したプロジェクトで使用されています。それは上に構築されていますADO.NET 現在のバージョンは NHibernate 4.0.4.

  • NHibernateはオープンソースの.NETオブジェクトリレーショナルマッパーであり、 GNU Lesser General Public License

  • これは、人気のあるJavaオブジェクトリレーショナルマッパーであるHibernateに基づいており、非常に成熟したアクティブなコードベースを備えています。

  • これは、オブジェクト指向ドメインモデルを従来のリレーショナルデータベースにマッピングするためのフレームワークを提供します。

  • NHibernateはによって開始されました Tom Barrett そしてこのプロジェクトは、彼らの最初のコミットである2003年2月から始まっています。

  • これは大きなプロジェクトであり、多くの機能を提供します。

  • あります NuGet package 利用可能で、プロジェクトへの追加が非常に簡単になります。

なぜNHibernate?

さて、問題はなぜ必要なのかということです object-relational mappers? これは、オブジェクトの世界とリレーショナルの世界の間に断絶があるためです。

  • オブジェクトの世界では、すべてが objects; 私たちはオブジェクトを私たちのデータを持つものと呼びました。

  • リレーショナルワールドはすべてセットベースであり、オブジェクトワールドとは異なるテーブルと行を処理しています。

  • オブジェクトの世界では、 unidirectional associations。顧客が注文へのポインタを持っている場合、それは必ずしも注文が顧客へのポインタを持っていることを意味するわけではなく、そうでない場合もあります。

  • リレーショナルの世界では、すべての関連付けは bidirectional そしてそれは外部キーによって行うことができます。

  • すべての関連付けは本質的に双方向であるため、オブジェクトリレーショナルマッピングを処理する場合は、この切断も処理する必要があります。

  • オブジェクトの世界では、単方向のポインターを使用していますが、リレーショナルの世界では、本質的に双方向の外部キーを使用しています。

  • オブジェクトの世界にはこの継承の概念があり、車両にはさまざまなサブクラスがあります。つまり、車は車両の一種であり、ボートは車両の一種であり、スポーツカーは自動車の一種です。継承関係。

  • リレーショナル世界には、この継承の概念はありません。

マッピング

では、これらすべてをどのようにマッピングするのでしょうか disjoint relationships?このマッピングの概念は、オブジェクトリレーショナルマッパーに由来します。次の図に示すように、理解すべきことは主に3つあります。

  • アプリケーションでは、クラス定義が必要になります。これは通常、C#コードと、Employeeクラス、Customerクラス、Orderクラスなどのクラスを表す.NETコードです。

  • 下部に、データベーススキーマが表示されます。これは Data Definition Language 顧客テーブルがどのように見えるか、従業員テーブルがどのように見えるかを指定するリレーショナルデータベース内。

  • これらの間に、行と列、および外部キーの関係に関して、C#のオブジェクトワールドからデータベースワールドに変換する方法をオブジェクトリレーショナルマッパーに指示するマッピングメタデータがあります。

  • このマッピングメタデータはさまざまな方法で表すことができ、NHibernateアプリケーションで最も一般的なこのさまざまな方法をいくつか見ていきます。

  • それはによって表されます HBM (Hibernate Mapping) XMLファイルであるファイル。

サポートされているデータベース

NHibernateは、さまざまなデータベースをサポートしています。そこにある既存のリレーショナルデータベースはすべてNHibernateにアクセスできます。

  • SQL Serverは、サポートされている主要なデータベースであり、ほとんどの開発者が開発中に使用しているものであり、おそらく最も一般的なものです。

  • また works very well with Oracle

  • また、DB2、Firebird、MySQL、PostgreSQL、SQLLiteもサポートしています。

  • それはまた持っています ODBC and OLEDB drivers

今日、多くのシステムは階層化アーキテクチャで設計されていますが、NHibernateにもそれがあり、その設計で完全に機能します。

階層化アーキテクチャ

階層化アーキテクチャは、システムをいくつかのグループに分割します。各グループには、特定の問題領域に対処するコードが含まれ、これらのグループはレイヤーと呼ばれます。エンタープライズレベルのアプリケーションのほとんどはhigh-level application architecture 3つの層で構成されている-

  • プレゼンテーション層
  • ビジネス層
  • 永続層

たとえば、プレゼンテーション層とも呼ばれるユーザーインターフェイス層には、Webページを構築してユーザー入力を処理するためのすべてのアプリケーションコードが含まれている場合があります。

階層化アプローチの主な利点の1つは、他の層を大幅に中断することなく1つの層に変更を加えることができるため、システムを作成できることです。 lesser fragile and more maintainable

プレゼンテーション層

  • これは最上位のレイヤーであり、ユーザーインターフェイス、ページ、ダイアログ、または画面の描画、ユーザー入力の収集、およびナビゲーションの制御を担当するコードが含まれています。

ビジネス層

  • ビジネス層は、ユーザーが問題ドメインの一部として理解するビジネスルールまたはシステム要件を実装する責任があります。

  • また、永続層によって定義されたモデルを再利用します。

永続層

  • 永続層は、アプリケーションデータの保存と取得を担当するクラスとコンポーネントで構成されます。

  • このレイヤーは、モデルクラスとデータベース間のマッピングも定義します。NHibernateは主にこのレイヤーで使用されます。

データベース

  • データベースは.NETアプリケーションの外部に存在します。
  • これは、システム状態の実際の永続的な表現です。
  • SQLデータベースを使用する場合、データベースにはリレーショナルスキーマと場合によってはストアドプロシージャが含まれます。

ヘルパー/ユーティリティクラス

  • すべてのアプリケーションには、他のレイヤーをサポートする一連のヘルパークラスまたはユーティリティクラスがあります。たとえば、UIウィジェット、メッセージングクラス、例外クラス、ロギングユーティリティなどです。

  • これらの要素は、階層化アーキテクチャの層間依存性の規則に従わないため、層とは見なされません。

NHibernateアーキテクチャ

  • これはNHibernateアプリケーションの高レベルのビューであり、単純なNHibernateアーキテクチャーも見ることができます。

  • アプリケーションコードはNHibernateを使用します ISession そして IQuery 永続化操作用のAPIであり、データベーストランザクションを管理するだけで済み、理想的にはNHibernateを使用します ITransaction API。

NHibernateの使用を実際に開始する前に、NHibernateが構築されている基盤を理解する必要があります。NHibernateは、オブジェクトリレーショナルマッピングまたはORMの概念に基づく永続化テクノロジです。

ORMとは何ですか?

オブジェクトリレーショナルマッピング(ORM)は programming techniqueオブジェクト指向プログラミング言語で互換性のない型システム間でデータを変換するため。つまり、アプリケーションのビジネスオブジェクトをリレーショナルデータベーステーブルにマッピングするという概念であり、アプリケーションのオブジェクトモデルを介してデータに簡単にアクセスして完全に更新できます。

  • すでにご存知のように、リレーショナルデータベースはデータを格納するための優れた手段を提供しますが、オブジェクト指向プログラミングは複雑なアプリケーションを構築するための優れたアプローチです。

  • NHibernateとORMは一般に、重要なビジネスロジック、ドメインモデル、およびある種のデータベースを備えたアプリケーションに最も関連しています。

  • ORMを使用すると、オブジェクトをリレーショナルデータに簡単に変換したり、元に戻したりできる変換レイヤーを非常に簡単に作成できます。

  • 頭字語ORMは、オブジェクトロールモデリングを意味する場合もあります。この用語は、オブジェクト/リレーショナルマッピングが関連するようになる前に考案されました。

  • データベースモデリングで使用される情報分析の方法について説明します。

なぜORMなのか?

ORMは framework これにより、オブジェクト指向言語で見つかったオブジェクトの世界を、リレーショナルデータベースで見つかったリレーショナルテーブルの行にマッピングできます。

この概念を理解するために、次の図を見てみましょう。

  • 上の図では、右側にEmployeeというテーブルがあり、個々の従業員に関連付けられた各データの列が含まれていることがわかります。

  • 各従業員を一意に識別するIDの列があります。

  • 従業員の名前の列、参加日の別の列、最後に従業員の年齢の列。

  • 新しい従業員をテーブルに格納するコードを記述したい場合、それはそれほど簡単ではありません。

  • 上の図では、ID、名前、参加日、年齢のフィールドを持つ従業員オブジェクトがあることもわかります。

  • ORMがない場合、このオブジェクトを、従業員データを従業員テーブルに挿入するいくつかの異なるSQLステートメントに変換する必要があります。

  • したがって、上記のシナリオを実行するSQLを作成するコードを作成することはそれほど難しくありませんが、少し面倒で、間違えるのは非常に簡単です。

  • NHibernateのようなORMを使用して、特定のクラスをリレーショナルテーブルにマップする方法を宣言し、ORMまたはNHibernateに、従業員テーブルのクエリデータに挿入、更新、削除するSQLを作成するという厄介な仕事を処理させることができます。

  • これにより、コードをオブジェクトの使用に集中させ、それらのオブジェクトを自動的にリレーショナルテーブルに変換することができます。

  • つまり、ORMが実際に行うことは、オブジェクトをテーブルに手動でマップする必要がなくなることです。

NHibernateでの作業を開始するには、VisualStudioとNHibernateパッケージが必要です。

VisualStudioのインストール

マイクロソフトは、 free version VisualStudioの SQL Server からダウンロードできます https://www.visualstudio.com インストールの手順は次のとおりです。

Step 1 −ダウンロードが完了したら、インストーラーを実行すると、次のダイアログボックスが表示されます。

Step 2 − [インストール]ボタンをクリックすると、インストールプロセスが開始されます。

Step 3 −インストールプロセスが正常に完了すると、次のダイアログボックスが表示されます。

Step 4 −このダイアログボックスを閉じ、必要に応じてコンピュータを再起動します。

Step 5−スタートメニューからVisual Studioを開き、次のダイアログを開きます。初めての準備には少し時間がかかります。

Step 6 −これがすべて完了すると、VisualStudioのメインウィンドウが表示されます。

NHibernateパッケージのインストール

NHibernateは、.NETFramework用の成熟したオープンソースのオブジェクトリレーショナルマッパーです。それは積極的に開発され、完全に機能し、何千もの成功したプロジェクトで使用されています。NHibernateパッケージは以下の方法でインストールできます。

直接ダウンロード

  • からファイルからzipをダウンロードします https://sourceforge.net/ これには、必要なすべてのバイナリが含まれています。

  • このzipファイルを抽出し、これらすべてのバイナリをプロジェクトに含めます。

NuGetを使用してインストールする

  • NHibernateをインストールするもう1つの方法は、NuGetを使用してNHibernateパッケージをインストールすることです。これは、NHibernateをプロジェクトに組み込む最も簡単な方法です。

  • すべてのNHibernate依存関係をダウンロードし、必要なすべてのアセンブリへの参照を作成します。

  • NHibernateをインストールするには、パッケージマネージャーコンソールで次のコマンドを実行します。

install-package NHibernate

これで、アプリケーションを開始する準備が整いました。

この章では、NHibernateを使用して簡単な例を開始する方法を見ていきます。私たちは構築しますsimple console application。コンソールアプリケーションを作成するには、作成する必要のあるすべての機能を含むVisual Studio 2015を使用し、NHibernateパッケージを使用してアプリケーションをテストします。

以下は、VisualStudioで使用可能なプロジェクトテンプレートを使用してプロジェクトを作成する手順です。

Step 1 − Visual Studioを開き、[ファイル]→[新規]→[プロジェクト]メニューオプションをクリックします。

Step 2 −新しいプロジェクトダイアログが開きます。

Step 3 −左側のペインから、[テンプレート]→[Visual C#]→[Windows]を選択します。

Step 4 −中央のペインで、[コンソールアプリケーション]を選択します。

Step 5 −「名前」フィールドにプロジェクト名「NHibernateDemoApp」を入力し、「OK」をクリックして続行します。

Step 6 −プロジェクトがVisual Studioによって作成されると、ソリューションエクスプローラーウィンドウにいくつかのファイルが表示されます。

簡単なコンソールアプリケーションプロジェクトを作成したことをご存知のとおり、コンソールプロジェクトにNHibernateパッケージを含める必要があります。

[ツール]メニューに移動し、[NuGetパッケージマネージャー]→[パッケージマネージャーコンソール]を選択すると、[パッケージマネージャーコンソール]ウィンドウが開きます。

上記のコマンドを指定してください Package Manager ConsoleウィンドウでEnterキーを押すと、すべてのNHibernate依存関係がダウンロードされ、必要なすべてのアセンブリへの参照が作成されます。インストールが完了すると、次の図に示すようなメッセージが表示されます。

NHibernateが追加されたので、実装を開始できます。したがって、非常に単純なマッピングから始めます。table と呼ばれる Student、IDと呼ばれる整数の主キーと、FirstName列とLastName列があります。

この学生を表すクラスが必要なので、ソリューションエクスプローラーでプロジェクトを右クリックし、[追加]→[クラス]を選択して[新しいアイテムの追加]ダイアログボックスを開き、Studentという新しいクラスを作成しましょう。

入る Student.cs名前フィールドで、[追加]ボタンをクリックします。このStudentクラスでは、IDと呼ばれる整数の主キーが必要であり、この文字列を作成する必要があります。FirstName そして LastName 次のStudentクラスの完全な実装に示されているフィールド。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 
   
   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstMidName { get; set; } 
   } 
}

NHibernateアプリケーションでモデルを扱う場合、すべてのフィールドを仮想化するのが最も簡単です。つまり、これは私たちが使用する単純なNHibernateモデルであり、これをバックエンドデータベースにマップします。

次に、ProgramクラスのMainメソッドに移動して、新しいNHibernate構成オブジェクトを作成しましょう。

私たちが最初に提供する必要があるのは connection string。これはデータベース固有の接続文字列であり、接続文字列を見つける最も簡単な方法は、データベースを右クリックすることです。SQL Server Object Explorer [プロパティ]を選択します。

[プロパティ]ウィンドウが開き、下にスクロールすると、[プロパティ]ウィンドウに[接続文字列]フィールドが表示されます。

接続文字列をコピーして、コードで指定します。以下は、NHibernateの構成が必要なMainメソッドの実装です。

using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;

using System;
using System.Linq;
using System.Reflection;

namespace NHibernateDemoApp {

   class Program {
   
      static void Main(string[] args) {
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
         
                     
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>();
         });
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly());
         
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()) {
         
            using (var tx = session.BeginTransaction()) {
               //perform database logic 
               tx.Commit();
            }
            
            Console.ReadLine(); 
         } 
      } 
   } 
}

接続文字列の後に、ドライバーを提供する必要があります。 SQLClientDriver 次に、SQL Serverのバージョンである方言を提供する必要があり、MS SQL2008を使用します。

NHibernateは、データベースに接続する方法を知っています。もう1つ行う必要があるのは、マップするモデルのリストを提供することです。

これは、アセンブリを追加することで実行できるため、 Assembly.GetExecutingAssemblyこれは、プログラムがマッピングファイルを見つける場所です。マッピングファイルは、NHibernateにC#クラスからデータベーステーブルに移動する方法を指示します。

SessionFactoryは、NHibernateの初期化に必要なすべてのメタデータをコンパイルします。SessionFactoryを使用して、データベース接続にほぼ類似したセッションを構築できます。したがって、適切な方法は、usingブロックで使用することです。私は言うことができますvar session 等しい sessionFactory.OpenSession トランザクション内でこれを実行したいと思います。

セッションが開かれると、新しいトランザクションを開始するようにセッションに指示できます。次に、ここでいくつかのロジックを実行できます。したがって、データベースロジックを実行し、最後にそのトランザクションをコミットします。

この章では、いくつかをカバーします basic mapping前の章から、データベーステーブルとC#クラス定義があることがわかります。ここで、C#からデータベースに変換して再度変換する方法を説明するマッピングが必要です。

それでは、ソリューションエクスプローラーでプロジェクトを右クリックし、[追加]→[新しいアイテム...]を選択して、新しいXMLファイルを追加しましょう。

入る Student.hbm.xml名前フィールドに。デフォルトのアセンブリを指定する必要があります。NHibernateDemoAppまた、デフォルトの名前空間を指定します。これにより、このファイルで作成する他の多くの型定義が短縮されます。

以下は、XMLファイルでの実装です-

<?xml version = "1.0" encoding = "utf-8" ?> 

<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">

   <class name = "Student"> 
      <id name = "ID">
        <generator class = "native"/> 
      </id> 
		
      <property name = "LastName"/> 
      <property name = "FirstMidName"/> 
   </class> 
   
</hibernate-mapping>

次にクラスを定義する必要があります。このクラスは私たちになりますStudent class。次に、NHibernateにIDの名前(ID)を指示する必要があります。また、NHibernateにIDの生成方法を指示する必要があるため、ジェネレーターはネイティブタイプになります。

ネイティブ型ジェネレーターは、SQL Serverのようなデータベースでは、ID列であるID型を使用することを意味します。

次にやらなければならないことは、プロパティの名前を付けることです。したがって、FirstNameとLastNameにさらに2つのプロパティを追加します。

現在、これらのマッピングファイルをアセンブリから読み取っています。したがって、これを行うための好ましい方法は、これらを持つことですHBM filesアセンブリに焼き付けました。これは、プロパティを設定するだけで実行できます。

ソリューションエクスプローラーでプロジェクトを右クリックし、[プロパティ]を選択すると、 Build Action field デフォルトでコンテンツが選択されています。

ドロップダウンリストから埋め込みリソースを選択します。

したがって、これは実際にそのXMLファイルを内部に埋め込みます NHibernateDemoApp アセンブリ。

この章では、基本的なことをカバーします CRUD operations。システムを起動する準備ができたので、ドメインStudentクラスを正常に実装したので、マッピングファイルを定義し、NHibernateを構成しました。これで、いくつかのクエリを使用してCRUD操作を実行できます。

データの作成

ご覧のとおり、Studentテーブルにはデータがありません。 NHibernateDemoDB データベース。

したがって、いくつかのデータを追加するには、を実行する必要があります Add/Create 以下に示す操作。

using (var session = sefact.OpenSession()) { 

   using (var tx = session.BeginTransaction()) { 
     
      var student1 = new Student { 
         ID = 1, 
         FirstMidName = "Allan", 
         LastName = "Bommer" 
      }; 
      
      var student2 = new Student { 
         ID = 2, 
         FirstMidName = "Jerry", 
         LastName = "Lewis" 
      }; 
      
      session.Save(student1); 
      session.Save(student2); 
      tx.Commit(); 
   } 
   
   Console.ReadLine(); 
}

ご覧のとおり、2人の生徒を作成してから、のSave()メソッドを呼び出します。 OpenSession 次に、のCommit()を呼び出します。 BeginTransaction。これがの完全な実装ですProgram.cs ファイル

using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 
   
   class Program { 
      
      static void Main(string[] args) { 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 

            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
         }); 
   
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
               
               var student1 = new Student { 
                  ID = 1,  
                  FirstMidName = "Allan", 
                  LastName = "Bommer" 
               }; 

               var student2 = new Student { 
                  ID = 2, 
                  FirstMidName = "Jerry", 
                  LastName = "Lewis" 
               }; 
            
               session.Save(student1); 
               session.Save(student2); 
               tx.Commit();
            } 
            
            Console.ReadLine(); 
         } 
      } 
   } 
}

次に、このアプリケーションを実行してから、SQLServerオブジェクトエクスプローラーに移動してデータベースを更新します。上記の2人の学生がNHibernateDemoDBデータベースのStudentテーブルに追加されていることがわかります。

学生テーブルからデータを読み取る

これで、studentテーブルに2つのレコードがあることがわかります。テーブルからこれらのレコードを読み取るには、を呼び出す必要がありますCreateCriteria() 次のコードに示すように、OpenSessionの

using (var session = sefact.OpenSession()) { 
   
   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>(); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", 
            student.ID,student.FirstMidName, student.LastName); 
      } 
      
      tx.Commit(); 
   } 
   
   Console.ReadLine(); 
}

したがって、レコードのリストが必要な場合は、単にStudentタイプのリストと言うことができます。

今使用します foreach すべての学生を通して、IDを印刷すると言います。 FirstMidName そして LastNameコンソールで。ここで、このアプリケーションを再度実行すると、コンソールウィンドウに次の出力が表示されます。

1 Allan Bommer
2 Jerry Lewis

でIDを指定して、任意のレコードを取得することもできます。 Get() 次のコードを使用したOpenSessionのメソッド。

using (var session = sefact.OpenSession()) { 
   
   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>(); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      }
      
      var stdnt = session.Get<Student>(1); 
      Console.WriteLine("Retrieved by ID"); 
      Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, 
         stdnt.FirstMidName, stdnt.LastName); 
      tx.Commit();
   } 
	
   Console.ReadLine(); 
}

これで、アプリケーションを実行すると、次の出力が表示されます。

1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer

更新記録

テーブルのレコードを更新するには、最初にその特定のレコードをフェッチしてから、を呼び出してそのレコードを更新する必要があります。 Update() 次のコードに示すOpenSessionのメソッド。

using (var session = sefact.OpenSession()) { 

   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>(); 
     
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      }
      
      var stdnt = session.Get<Student>(1); 
      Console.WriteLine("Retrieved by ID"); 
      Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
      
      Console.WriteLine("Update the last name of ID = {0}", stdnt.ID); 
      stdnt.LastName = "Donald"; 
      session.Update(stdnt); 
      Console.WriteLine("\nFetch the complete list again\n"); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      } 
      
      tx.Commit();
   } 
   
   Console.ReadLine();
}

これで、アプリケーションを実行すると、次の出力が表示されます。

1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Update the last name of ID = 1
Fetch the complete list again
1 Allan Donald
2 Jerry Lewis

ご覧のとおり、IDが1のLastNameがBommerからDonaldに更新されています。

レコードを削除する

テーブルからレコードを削除するには、最初にその特定のレコードをフェッチしてから、を呼び出してそのレコードを削除する必要があります。 Delete() 次のコードに示すOpenSessionのメソッド。

using (var session = sefact.OpenSession()) { 
   
   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>();
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      }
      
      var stdnt = session.Get<Student>(1); 
      Console.WriteLine("Retrieved by ID"); 
      Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
      
      Console.WriteLine("Delete the record which has ID = {0}", stdnt.ID); 
      session.Delete(stdnt);
      Console.WriteLine("\nFetch the complete list again\n"); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName, 
            student.LastName); 
      } 
      
      tx.Commit();
   } 
	
   Console.ReadLine(); 
}

これで、アプリケーションを実行すると、次の出力が表示されます。

1 Allan Donald
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Delete the record which has ID = 1
Fetch the complete list again
2 Jerry Lewis

ご覧のとおり、IDが1のレコードはデータベースで使用できなくなりました。データベースは、SQLServerオブジェクトエクスプローラーでも確認できます。

この章では、データベースのすべてのレコードがどのようになっているのかを理解します retrieved, updated, created, and deleted そして、これらのクエリはどの程度正確に実行されますか?

これらすべてを理解するために、SQLをコンソールに記録するオプションを構成に追加するだけです。これはSQLクエリをログに記録する簡単なステートメントです-

x.LogSqlInConsole = true;

これで、NHibernateDemoDBデータベースのstudentテーブルに2つのレコードがあります。次のコードに示すように、データベースからすべてのレコードを取得してみましょう。

using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 

   class Program { 
      
      static void Main(string[] args) { 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;			
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
            
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 
      
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory();
      
         using (var session = sefact.OpenSession()) { 
         
            using (var tx = session.BeginTransaction()) { 
               Console.WriteLine("\nFetch the complete list again\n");
               var students = session.CreateCriteria<Student>().List<Student>(); 
      
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
                     student.LastName); 
               } 
               
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

それでは、先に進んでこのアプリケーションを再度実行すると、次の出力が表示されます-

NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
   this_.FirstMidName as FirstMid3_0_0_ FROM Student this_

Fetch the complete list again

3 Allan Bommer
4 Jerry Lewis

ご覧のとおり、 select clauseデータベースに送信されるのは、実際にはID、FirstMidName、LastNameを取得する句のようなものです。したがって、これはすべてデータベースに送信されてそこで処理されるのであり、多くのレコードがサーバーに戻されてサーバー側で処理されるのではありません。

NHibernateプロファイラー

これらの結果を確認する別の方法は、NHibernateProfilerを使用することです。NHibernate Profilerは商用ツールですが、NHibernateアプリケーションでの作業に非常に役立ちます。NHibernateプロファイラーはNuGetからアプリケーションに簡単にインストールできます。

NuGetパッケージマネージャー→パッケージマネージャーコンソールを選択して、[ツール]メニューからNuGetマネージャーコンソールに移動しましょう。パッケージマネージャーコンソールウィンドウが開きます。次のコマンドを入力して、Enterキーを押します。

PM> install-package NHibernateProfiler

NHibernate Profilerに必要なすべてのバイナリがインストールされます。正常にインストールされると、次のメッセージが表示されます。

また、NHibernate Profilerがインストールされると、起動されることがわかります。使用するにはライセンスが必要ですが、デモの目的で、NHibernateProfilerの30日間の試用版を使用できます。

これで、NHibernate ProfilerがWebアプリケーションで動作するように最適化され、追加されたことがわかります。 App_Start folderソリューションエクスプローラーで。これらすべてを単純にするために、App_Startフォルダーを削除すると、ProgramクラスのMainメソッドの先頭に1つのステートメントが追加されていることがわかります。

App_Start.NHibernateProfilerBootstrapper.PreStart();

このステートメントも削除し、単純な呼び出しを追加するだけです NHibernateProfiler.Initialize 次のコードに示すように。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 
   
   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;			
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 

         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()) { 
            
            using (var tx = session.BeginTransaction()){ 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n");
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
                     student.LastName); 
               } 
					
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   
   }
}

これで、アプリケーションを実行すると、NHibernateProfilerアプリケーションにデータが送信されます。

ここで、トランザクションを開始したこと、SQLがデータベースに対して行っていることを適切な形式で示す優れた表示があります。

したがって、これはNHibernateアプリケーション内で何が起こっているのかを正確に判断するのに非常に役立ちます。アプリケーションがある程度複雑になると、SQLプロファイラーのようなものが必要になりますが、NHibernateの知識があれば、非常に便利になります。

この章では、追加します IntelliSense NHibernateマッピングファイルに (*.hbm.xml files)。ドメインStudentクラスのマッピング中に観察したように、現在IntelliSenseは利用できません。持っていると非常に便利ですXML schemas利用可能です。したがって、この章では、これらのNHibernateXMLファイル用にVisualStudioでIntelliSenseを追加する方法を理解します。

マッピングファイルを開くと、メインメニューにXMLメニューオプションが表示されます。

[XML]→[スキーマ...]メニューオプションを選択すると、[XMLスキーマ]ダイアログボックスが表示されます。

ダイアログボックスの右上にある[追加...]ボタンを選択すると、ファイルダイアログが開きます。今すぐに行きますpackages folder、プロジェクトのSolutionフォルダーにあり、プロジェクトに含まれているさまざまなパッケージが表示されます。

次に、をダブルクリックします NHibernate.4.*** folder NHibernateの構成とマッピングを定義する2つのスキーマ(* .xsd)ファイルまたはXMLスキーマ定義ファイルが表示されます。

これらの2つのスキーマファイルを選択し、[開く]ボタンをクリックします。

NHibernateスキーマが[XMLスキーマ]ダイアログに追加されていることがわかります。[OK]ボタンをクリックします。それでは、新しいプロパティタグを開始してみましょう。ここに、完全なIntelliSenseがあることがわかります。

IntelliSenseが利用可能になり、オブジェクトリレーショナルマッピングの時間を大幅に節約できます。

この章では、マッピングデータ型について説明します。エンティティのマッピングは簡単です。エンティティクラスは常にを使用してデータベーステーブルにマッピングされます。<class>, <subclass>, and <joined-subclass>マッピング要素。値型にはさらに何かが必要です。そこではマッピング型が必要になります。

NHibernateは、さまざまなデータ型をマッピングできます。サポートされている最も一般的なデータ型のリストは次のとおりです。

マッピングタイプ .NETタイプ System.Data.DbType
Int16 System.Int16 DbType.Int16
Int32 System.Int32 DbType.Int32
Int64 System.Int64 DbType.Int64
シングル System.Single DbType.Single
ダブル System.Double DbType.Double
10進数 System.Decimal DbType.Decimal
ストリング System.String DbType.String
AnsiString System.String DbType.AnsiString
バイト System.Byte DbType.Byte
チャー System.Char DbType.StringFixedLength-1文字
AnsiChar System.Char DbType.AnsiStringFixedLength-1文字
ブール値 System.Boolean DbType.Boolean
GUID System.Guid DbType.Guid
PersistentEnum System.Enum(列挙型) 基になる値のDbType
真/偽 System.Boolean DbType.AnsiStringFixedLength-「T」または「F」のいずれか
はい・いいえ System.Boolean DbType.AnsiStringFixedLength-「Y」または「N」のいずれか
日付時刻 日付時刻 DbType.DateTime-ミリ秒を無視します
ダニ System.DateTime DbType.Int64
期間 System.TimeSpan DbType.Int64
タイムスタンプ System.DateTime DbType.DateTime-データベースがサポートするのと同じくらい具体的
バイナリ System.Byte [] DbType.Binary
BinaryBlob System.Byte [] DbType.Binary
StringClob System.String DbType.String
シリアル化可能 SerializableAttributeでマークされたSystem.Object DbType.Binary
CultureInfo System.Globalization.CultureInfo DbType.String-カルチャ用の5文字
タイプ システムタイプ アセンブリ修飾名を保持するDbType.String

上記の表は、以下のポインタを詳細に説明しています。

  • 単純な数値タイプから文字列まで、を使用してさまざまな方法でマッピングできます。 varchars, chars など、文字列BLOB、およびデータベースがサポートするさまざまなタイプのすべて。

  • マッピングすることもできます Booleans、0と1を使用するフィールド、true、false、またはTとFを含む文字フィールドの両方。

  • データベース内のバックエンドのブール値にマップする方法を定義するには、さまざまな方法があります。

  • のマッピングを処理できます DateTime、タイムゾーンオフセット、夏時間などを含む場合と含まない場合の両方。

  • マップすることもできます enumerations; これらを文字列またはその基になる数値にマップできます。

データベースとStudentクラスの両方に同じプロパティ名がある簡単な例を見てみましょう。

次に、学生クラスでFirstMidNameをFirstNameに変更します。ここでは、FirstMidName列は変更しませんが、NHibernateにこの変換を実行するように指示する方法を説明します。以下は、更新された学生クラスです。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 
  
   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
   }
}

これがNHibernateマッピングファイルの実装です。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemoApp" 
   namespace = "NHibernateDemoApp"> 
   
   <class name = "Student">
	
      <id name = "ID"> 
         <generator class = "native"/>
      </id> 
   
      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
   </class> 

</hibernate-mapping>

この例では、FirstNameフィールドが.NET文字列であり、FirstMidName列が SQL nvarchar。NHibernateにこの変換の実行方法を指示するには、名前を次のように設定します。FirstName および列が等しい FirstMidName そして、この特定の変換に適した文字列に等しいマッピングタイプを指定します。

以下は Program.cs ファイルの実装。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 

   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
            
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory();
			
         using (var session = sefact.OpenSession()) { 
            
            using (var tx = session.BeginTransaction()) { 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstName,
                     student.LastName); 
               } 
					
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   }
}

これで、アプリケーションを実行すると、次の出力が表示されます。

NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_, 
   this_.FirstMidName as FirstMid3_0_0_ FROM Student this_

Fetch the complete list again
3 Allan Bommer
4 Jerry Lewis

ご覧のとおり、データベース内の列名に別のプロパティ名がマップされています。

のStudentクラスに別のプロパティを追加する別の例を見てみましょう。 enumタイプ。これがStudentクラスの実装です。

using System; 
using System.Collections.Generic; 
using System.Linq; using System.Text; 
using System.Threading.Tasks; 

namespace NHibernateDemoApp { 
   
   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual StudentAcademicStanding AcademicStanding { get; set; } 
   } 
   
   public enum StudentAcademicStanding { 
      Excellent, 
      Good, 
      Fair, 
      Poor, 
      Terrible 
   } 
}

ご覧のとおり、列挙には、Excellent、Good、Fair、Poor、Terribleなど、さまざまな値が含まれている可能性があります。

マッピングファイルにジャンプすると、これらの各プロパティが、新しく追加されたものを含むマッピングファイルにリストされていることがわかります。 AcademicStanding プロパティ。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp"> 
   
   <class name = "Student"> 
	
      <id name = "ID"> 
         <generator class = "native"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 
   </class>  

</hibernate-mapping>

ここで、データベースも変更する必要があるため、SQL Serverオブジェクトエクスプローラーに移動し、データベースを右クリックして、[新しいクエリ...]オプションを選択します。

クエリエディタを開き、以下のクエリを指定します。

DROP TABLE [dbo].[Student]

CREATE TABLE [dbo].[Student] ( 
   [ID] INT IDENTITY (1, 1) NOT NULL, 
   [LastName] NVARCHAR (MAX) NULL, 
   [FirstMidName] NVARCHAR (MAX) NULL, 
   [AcademicStanding] NCHAR(10) NULL, 
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC) 
);

このクエリは、最初に既存の学生テーブルを削除してから、新しいテーブルを作成します。

上に示すように、実行アイコンのClcik。クエリが正常に実行されると、メッセージが表示されます。

データベースとテーブルのドロップダウンを展開し、学生テーブルを右クリックして、ビューデザイナを選択します。

これで、新しく作成されたテーブルが表示されます。このテーブルには、新しいプロパティAcademicStandingもあります。

次のように2つのレコードを追加しましょう Program.cs ファイル。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 

   class Program { 
      
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
            
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
         }); 
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()) { 
            using (var tx = session.BeginTransaction()) { 
               
               var student1 = new Student { 
                  ID = 1, 
                  FirstName = "Allan", 
                  LastName = "Bommer",
                  AcademicStanding = StudentAcademicStanding.Excellent 
               };
               
               var student2 = new Student { 
                  ID = 2, 
                  FirstName = "Jerry", 
                  LastName = "Lewis", 
                  AcademicStanding = StudentAcademicStanding.Good 
               };
					
               session.Save(student1); 
               session.Save(student2);
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n");
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName, student.LastName, student.AcademicStanding); 
               } 
					
               tx.Commit(); 
            }
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

次に、アプリケーションを実行してみましょう。コンソールウィンドウに次の出力が表示されます。

Fetch the complete list again

1 Allan Bommer Excellent
2 Jerry Lewis Good

それでは、Student Tableを右クリックして、データベースを調べてみましょう。

[データの表示]を選択すると、次のスクリーンショットに示すように、学生テーブルに2つのレコードが表示されます。

2つのレコードが追加され、AllanにはAcademicStanding 0があり、JerryにはAcademicStanding 1があることがわかります。これは、.Netでは最初の列挙値がデフォルトで0であるためです。これは、見てみると優れています。 StudentAcademicStanding。一方、Student.csファイルではGoodが2番目であるため、値は1です。

この章では、NHibernateの構成について説明します。NHibernateを構成する方法はいくつかあります。それは2つの主要なグループに分かれます

  • XMLベースの構成
  • コードベースの構成

コードベースの構成

コードベースの構成はNHibernateに組み込まれています。これはNHibernate3の周りに導入され、これまでコードベース構成を使用してきました。

String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;

cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
   Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
   TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
   
   x.Driver<SqlClientDriver>(); 
   x.Dialect<MsSql2008Dialect>(); 
   x.LogSqlInConsole = true; 
}); 

cfg.AddAssembly(Assembly.GetExecutingAssembly());

すべての構成はC#コードで指定されています。ここで、新しい構成オブジェクトを取得したことがわかります。次に、loquacious configurationこれは、データベースを構成するためにNHibernate3.1で導入されました。使用している接続文字列、接続しているデータベース、および使用する方言。また、マッピングアセンブリをここに直接追加します。

XMLベースの構成

XMLベースの構成を使用している場合は、 hibernate.cfg.xml ファイル。NHibernateスキーマを使用したスタンドアロンのxmlファイルです。または、そのNHibernate固有の構成をアプリ内に埋め込むこともできます。 web.cfg。hibernate.cfg.xmlの名前はデフォルトですが、そのxmlファイルにも任意の名前を使用できます。

NHibernateDemoAppプロジェクトに新しいxmlファイルを追加し、それをhibernate.cfg.xmlと呼んで、XMLベースの構成を調べてみましょう。

次の情報をhibernate.cfg.xmlファイルに入力します。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2"> 
   <session-factory> 
   
      <property name = "connection.connection_string">
         Data Source = asia13797\\sqlexpress;
         Initial Catalog = NHibernateDemoDB;
         Integrated Security = True;
         Connect Timeout = 15;
         Encrypt = False;
         TrustServerCertificate = False;
         ApplicationIntent = ReadWrite;
         MultiSubnetFailover = False;
      </property> 
      
      <property name = "connection.driver_class">
         NHibernate.Driver.SqlClientDriver
      </property> 
		
      <property name = "dialect">
         NHibernate.Dialect.MsSql2008Dialect
      </property> 
		
      <mapping assembly = "NHibernateDemoApp"/>
		
   </session-factory> 
	
</hibernate-configuration>

上記のxmlファイルでわかるように、C#で説明したものと同じ構成を指定しています。

次に、Program.csファイルからこの構成についてコメントし、 Configure() メソッド、ロードします hibernate.cfg.xml 以下に示すようにファイルします。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection; 

namespace NHibernateDemoApp { 

   class Program { 
      
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         //cfg.DataBaseIntegration(x =>
         
         //{ 
            // x.ConnectionString = "Data Source = asia13797;\\sqlexpress
            Initial Catalog = NHibernateDemoDB;
            Integrated Security = True;
            Connect Timeout = 15;
            Encrypt =False;
            TrustServerCertificate = False;
            ApplicationIntent = ReadWrite;
            MultiSubnetFailover = False"; 
            
            // x.Driver<SqlClientDriver>(); 
            // x.Dialect<MsSql2008Dialect>(); 
            // x.LogSqlInConsole = true; 
         //}); 
         
         //cfg.AddAssembly(Assembly.GetExecutingAssembly());
         cfg.Configure();
         var sefact = cfg.BuildSessionFactory();
			
         using (var session = sefact.OpenSession()) { 
            
            using (var tx = session.BeginTransaction()) { 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName, student.LastName, student.AcademicStanding); 
               } 
					
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

アプリケーションを再度実行すると、同じ出力が表示されます。

Fetch the complete list again

1 Allan Bommer Excellent
2 Jerry Lewis Good

この章では、NHibernate構成をオーバーライドする方法について説明します。覚えておく必要のあることがいくつかあります。

  • まず第一に、NHibernateの構成は付加的です。

  • したがって、単一のxmlファイルを使用する必要はなく、コードベースの構成や流暢なNHibernateを使用する必要もありません。

  • アプリケーションの構成方法に応じて、これらすべての方法を組み合わせることができます。

  • 覚えておくべき重要な点は、最後に構成が優先されるということです。

次の例では、構成オブジェクトを作成し、コードベースの構成を使用して構成し、最後にを呼び出すことがわかります。 cfg.configure() hibernate.cfg.xmlファイルをロードするメソッド。

String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;

cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
   Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
   TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
	
   x.Driver<SqlClientDriver>(); 
   x.Dialect<MsSql2008Dialect>(); 
   x.LogSqlInConsole = true; 
}); 

cfg.Configure();
  • したがって、hibernate.cfg.xml内のすべてのものは、コードベースの構成によって設定された設定をオーバーライドします。

  • これらの2つのプロセスを逆にすることで、hibernate.cfg.xml内でデフォルトを設定し、コードベースの構成内でオーバーライドを実行できます。

  • コードベースの構成を使用している場合を除外するものはなく、hibernate.cfg.xmlファイルの使用を妨げるものもありません。

xmlベースの構成とコードベースの構成を組み合わせて使用​​して構成をオーバーライドする簡単な例を見てみましょう。

また、接続文字列をに移動しましょう app.config 次のコードを使用してファイルします。

<?xml version = "1.0" encoding = "utf-8" ?> 

<configuration> 
   
   <startup> 
      <supportedRuntime version = "v4.0" sku = ".NETFramework,Version = v4.5" /> 
   </startup> 
   
   <connectionStrings> 
      <add name = "default" connectionString = "Data Source =
         asia13797\\sqlexpress;
         Initial Catalog = NHibernateDemoDB;
         Integrated Security = True;
         Connect Timeout = 15;
         Encrypt = False;
         TrustServerCertificate = False;
         ApplicationIntent = ReadWrite;
         MultiSubnetFailover = False"/> 
   </connectionStrings> 

</configuration>

接続文字列がいくつかに座っています app.configデフォルト名のファイル。ここで、接続文字列の代わりに、hibernate.cfg.xmlファイルにデフォルト名を記載する必要があります。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2"> 

   <session-factory> 
      <property name = "connection.connection_string">default</property> 
		
      <property name = "connection.driver_class">
         NHibernate.Driver.SqlClientDriver
      </property> 
		
      <property name = "dialect">
         NHibernate.Dialect.MsSql2008Dialect
      </property> 
		
      <mapping assembly = "NHibernateDemoApp"/> 
   </session-factory> 

</hibernate-configuration>

プログラムがhibernate.cfg.xmlファイルから読み取るため、コードベースの構成の接続文字列部分、ドライバー、および方言部分についてコメントしましょう。 LogSqlInConsole 一部はコードベースの構成のままになります。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 
   
   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { //x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            //x.Driver<SqlClientDriver>(); 
            //x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 
         
         cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
               
               var students = session.CreateCriteria<Student>().List<Student>();
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                  student.FirstName, student.LastName, student.AcademicStanding); 
               } 
					
               tx.Commit(); 
            }
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

これで、アプリケーションを実行すると、プログラムがコードベースの構成からログを読み取り、hibernate.cfg.xmlファイルから他の構成を読み取ったことがわかります。

NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,   
   this_.FirstMidName as FirstMid3_0_0_, this_.AcademicStanding as Academic4_0_0_ FROM
   Student this_

Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good

これで、構成の一部が内部にあります。 hibernate.cfg.xml ファイル、その一部はコードベースの構成内にあり、コードベースとの呼び出しの順序によって異なります configure()、どちらをオーバーライドするかを変更できます。

この章では、バッチサイズの更新について説明します。バッチサイズにより、control the number of updates サポートされているデータベースのデータベースへの1回のラウンドトリップで送信されます。

  • 更新バッチサイズは、NHibernate3.2の時点でデフォルトになっています。

  • ただし、以前のバージョンを使用している場合、またはNHibernateアプリケーションを調整する必要がある場合は、更新バッチサイズを確認する必要があります。これは、NHibernateのパフォーマンスを調整するために使用できる非常に便利なパラメーターです。

  • 実際のバッチサイズは、グループ内でデータベースにプッシュする挿入の数を制御します。

  • 現時点では、基盤となるデータベースプロバイダーがクエリのバッチ処理をサポートする必要があるため、SQLServerとOracleのみがこのオプションをサポートしています。

バッチサイズを10に設定して、セットに10レコードを挿入する簡単な例を見てみましょう。

cfg.DataBaseIntegration(x => { 
  
   x.ConnectionString = "default"; 
   x.Driver<SqlClientDriver>(); 
   x.Dialect<MsSql2008Dialect>(); 
   x.LogSqlInConsole = true; 
   x.BatchSize = 10; 

});

これは、25レコードがデータベースに追加される完全な実装です。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp {
   
   class Program {
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
         
            x.Driver>SqlClientDriver<(); 
            x.Dialect>MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory();
			
         using (var session = sefact.OpenSession()) {
			
            using (var tx = session.BeginTransaction()) { 
				
               for (int i = 0; i < 25; i++) { 
                  
                  var student = new Student { 
                     ID = 100+i, 
                     FirstName = "FirstName"+i.ToString(), 
                     LastName = "LastName" + i.ToString(), 
                     AcademicStanding = StudentAcademicStanding.Good 
                  };
						
                  session.Save(student); 
               } 
					
               tx.Commit();
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,student.FirstName,
                     student.LastName, student.AcademicStanding); 
               } 
            } 
				
            Console.ReadLine(); 
         } 
      }
   } 
}

それでは、アプリケーションを実行してみましょう。これらの更新がすべてNHibernateプロファイラーにジャンプしていることがわかります。データベースへの26回の個別往復があり、挿入と学生のリストの取得が25回行われます。

さて、それはなぜですか?その理由は、NHibernateがselect scope identity 次のコードに示すように、IDのマッピングファイルでネイティブ識別子生成戦略を使用しているためです。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" 
   namespace = "NHibernateDemoApp"> 
   
   <class name = "Student"> 

      <id name = "ID"> 
         <generator class = "native"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 
   
   </class> 
</hibernate-mapping>

したがって、次のような別の方法を使用する必要があります。 guid.comb方法。guid.combにアクセスする場合は、お客様のところに行き、これをに変更する必要があります。guid。だからそれはうまくいくでしょう。次に、次のコードを使用して、ネイティブからguid.combに変更しましょう。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly =
   "NHibernateDemoApp" namespace = "NHibernateDemoApp"> 
   <class name = "Student"> 

      <id name = "ID"> 
         <generator class = "guid.comb"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 

   </class> 

</hibernate-mapping>

したがって、これらのIDの生成を担当するのはデータベースです。NHibernateが生成されたIDを見つける唯一の方法は、直後にそれを選択することでした。そうしないと、学生のバッチを作成した場合、作成された学生のIDと一致させることができません。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 

   class Student { 
      public virtual Guid ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual StudentAcademicStanding AcademicStanding { get; set; }
   } 
	
   public enum StudentAcademicStanding { 
      Excellent, 
      Good, 
      Fair, 
      Poor, 
      Terrible 
   }
}

データベースを更新する必要があります。学生テーブルを削除し、次のクエリを指定して新しいテーブルを作成しましょう。SQLServerオブジェクトエクスプローラーに移動し、データベースを右クリックして、New Query…オプション。

クエリエディタを開き、次のクエリを指定します。

DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] ( 

   -- [ID] INT IDENTITY (1, 1) NOT NULL, 
   [ID] UNIQUEIDENTIFIER NOT NULL, 
   [LastName] NVARCHAR (MAX) NULL, 
   [FirstMidName] NVARCHAR (MAX) NULL, 
   [AcademicStanding] NCHAR(10) NULL, 
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC) 
);

このクエリは、最初に既存の学生テーブルを削除してから、新しいテーブルを作成します。ご覧のとおり、UNIQUEIDENTIFIER IDとして整数の主キーを使用するのではなく。

このクエリを実行してから、 Designer view 次の図に示すように、IDが一意の識別子で作成されていることがわかります。

次に、データを挿入するときに、program.csファイルからIDを削除する必要があります。これにより、IDが生成されます。 guids 自動的に。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 
   
   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize();
         var cfg = new Configuration();

         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true;
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
				
               for (int i = 0; i > 25; i++) { 
                  
                  var student = new Student { 
                     FirstName = "FirstName"+i.ToString(), 
                     LastName = "LastName" + i.ToString(), 
                     AcademicStanding = StudentAcademicStanding.Good 
                  }; 
                  
                  session.Save(student); 
               } 
					
               tx.Commit(); 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName,student.LastName, student.AcademicStanding);
               } 
            
            }
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

ここで、アプリケーションを再度実行し、NHibernateプロファイラーを確認します。これで、NHibernateプロファイラーは26回の往復ではなく、4回だけになります。

テーブルに10行、次にさらに10行、その後残りの5行が挿入されます。そして、コミット後、すべてのレコードを取得するためにもう1つ挿入しました。

  • それで、それはそれを可能な限り10のグループに分けました。

  • したがって、多くの挿入を行う場合は、バッチ処理できるため、アプリケーションの挿入パフォーマンスを劇的に向上させることができます。

  • これは、NHibernateがを使用してそれらのガイド自体を割り当てるためです。 guid.comb アルゴリズムであり、これを行うためにデータベースに依存する必要はありません。

  • したがって、バッチサイズを使用することは、それを調整するための優れた方法です。

この章では、 cachingNHibernateアプリケーションで動作します。キャッシュのサポートが組み込まれています。単純な機能のように見えますが、実際には最も複雑な機能の1つです。まず、第1レベルのキャッシュから始めます。

第1レベルのキャッシュ

このキャッシュメカニズムはNHibernateでデフォルトで有効になっており、キャッシュを操作するために何もする必要はありません。これを理解するために、データベースに2つのレコードがあることがわかるので、簡単な例を見てみましょう。

この例では、IDが1の学生を取得し、次のコードに示すように、同じセッションクエリを2回使用します。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cache; 
using NHibernate.Cfg; 
using NHibernate.Dialect;
using NHibernate.Driver; 
using NHibernate.Linq; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 
   
   class Program { 
      static void Main(string[] args) {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         
         cfg.Cache(c => { 
            c.UseMinimalPuts = true; 
            c.UseQueryCache = true; 
         }); 
			
         cfg.SessionFactory().Caching .Through<HashtableCacheProvider>()
            .WithDefaultExpiration(1440); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()){ 
			
            using (var tx = session.BeginTransaction()) { 
               var studentUsingTheFirstQuery = session.Get<Student>(1);
               var studentUsingTheSecondQuery = session.Get<Student>(1); 
            } 
            
            Console.ReadLine(); 
         } 
      } 
   } 
}

それでは、このアプリケーションを実行して、NHibernateプロファイラーで結果を確認しましょう。

NHibernateが1つのクエリのみを実行するのを見て驚かれることでしょう。これは、NHibernateが第1レベルのキャッシュを使用する方法です。最初のクエリが実行されると、NHibernateはID = 1のStudentを最初のレベルのキャッシュにキャッシュしました。

したがって、2番目のクエリが実行されると、NHibernateは最初にID = 1の第1レベルのキャッシュStudentエンティティを検索し、そのエンティティが見つかった場合、NHibernateは、同じ従業員オブジェクトを再度取得するために別のクエリを実行する必要がないことを認識します。 。

この章では、コンポーネントのマッピングについて説明します。NHibernateでは、component is a value object。それはそれ自身のアイデンティティを持っていません。

  • この例としては、お金のオブジェクト、財布、財布にお金が入っている場合がありますが、そのお金の正確な身元は関係ありません。

  • 独自の主キーはありませんが、コンポーネント自体は所有するオブジェクトと同じテーブルに永続的です。

学生がアドレスを持っている簡単な例を見てみましょう。これはのオブジェクトです。 Location class それに関連付けられています。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 

   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual StudentAcademicStanding AcademicStanding { get; set; } 
      public virtual Location Address { get; set; } 
   }

   public class Location { 
      public virtual string Street { get; set; } 
      public virtual string City { get; set; } 
      public virtual string Province { get; set; } 
      public virtual string Country { get; set; } 
   }
  
   public enum StudentAcademicStanding { 
      Excellent, 
      Good, 
      Fair, 
      Poor, 
      Terrible 
   } 
}

次に、次のクエリを実行してデータベースを更新する必要があります。これにより、最初にStudentテーブルが削除され、次にLocationクラスの列も含む新しいテーブルが作成されます。

DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] ( 

   [ID] INT IDENTITY (1, 1) NOT NULL, 
   [LastName] NVARCHAR (MAX) NULL, 
   [FirstMidName] NVARCHAR (MAX) NULL, 
   [AcademicStanding] NCHAR(10) NULL, 
   [Street] NVARCHAR (100) NULL, 
   [City] NVARCHAR (100) NULL, 
   [Province] NVARCHAR (100) NULL, 
   [Country] NVARCHAR (100) NULL, 
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC) 

);

次に、Studentクラスの一部ではないが、Locationクラスのプロパティであり、LocationクラスオブジェクトがStudentクラスで定義されている列をマップします。正しくマッピングするにはコンポーネントが必要です。でコンポーネントを作成しましょうstudent.hbm.xml 次のコードに示すようにファイル。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp"> 

   <class name = "Student"> 
      <id name = "ID"> 
         <generator class = "native"/>
      </id> 
   
      <property name = "LastName"/> 
		
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 
   
   </class> 
</hibernate-mapping>

このコンポーネントはアドレスであり、これらのさまざまなプロパティがあります。この情報により、NHibernateは実際にこれをマッピングできるようになりました。

これがProgram.csファイルで、新しい学生オブジェクトが作成および初期化されてからデータベースに保存されます。次に、データベースからリストを取得します。

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cache; 
using NHibernate.Caches.SysCache; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 

   class Program {
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration();

         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;			
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
         }); 
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
               
               var student1 = new Student { 
                  ID = 1, 
                  FirstName = "Allan", 
                  LastName = "Bommer", 
                  AcademicStanding = StudentAcademicStanding.Poor, 
                  
                  Address = new Location { 
                     Street = "123 Street", 
                     City = "Lahore", 
                     Province = "Punjab", 
                     Country = "Pakistan" 
                  } 
               }; 
					
               session.Save(student1); 
               tx.Commit(); 
               var students = session.Query<Student>().ToList<Student>();
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3} \t{4} \t{5} \t{6} \t{7}", 
                     student.ID, 
                     student.FirstName, 
                     student.LastName, 
                     student.AcademicStanding, 
                     student.Address.Street, 
                     student.Address.City, 
                     student.Address.Province, 
                     student.Address.Country
                  ); 
               } 
            } 
            Console.ReadLine(); 
         } 
      }
   } 
}

これでこのアプリケーションを実行でき、NHibernateはそれらの値をデータベースに保存できます。アプリケーションを実行すると、次の出力が表示されます。

Fetch the complete list again

2 Allan Bommer Poor 123 Street Lahore Punjab Pakistan

データベースの値は次のとおりです。

コンポーネントを使用すると、データベーステーブルにある列を独自の個別のクラスに分離できます。

  • ここでもう1つ注意すべき点は、Locationはクラスであり、エンティティではないためです。

  • これは値型オブジェクトであり、独自の主キーを持っていません。

  • それを含むStudentと同じテーブルに保存されます。

  • そのため、ここではコンポーネントを使用しています。

  • これにより、クラスレイヤー、クラスの定義方法、データベースのレイアウト方法を柔軟に変更できます。

この章では、NHibernateの関係について説明します。NHibernateの関係をどのように理解できるかに注意を向けましょう。最も簡単な方法は、データベースの観点から関係について考えることです。

  • 最初に、顧客と注文エンティティの間にいくつかの関係を作成する新しいアプリケーションを作成します。

  • これから説明する最初の関係は、古典的なコレクションの関係です。

  • 注文のコレクションを持つ顧客がいます。

  • これは1対多の関係であり、データベースでは2つのテーブルで表され、注文テーブルには顧客IDがあり、顧客との外部キー関係があります。

まず、データベースと、CustomerとOrderの2つのテーブルを作成する必要があります。これは、SQLServerエクスプローラーで次のクエリを指定することで作成できます。

USE [master] 
GO 
CREATE DATABASE [NHibernateDemo] 
GO 
USE [NHibernateDemo] 
GO

CREATE TABLE [dbo].[Customer]( 
   [Id] [uniqueidentifier] NOT NULL, 
   [FirstName] [nvarchar](100) NOT NULL, 
   [LastName] [nvarchar](100) NOT NULL, 
   [Points] [int] NULL, [HasGoldStatus] [bit] NULL, 
   [MemberSince] [date] NULL, 
   [CreditRating] [nchar](20) NULL, 
   [AverageRating] [decimal](18, 4) NULL, 
   [Street] [nvarchar](100) NULL, 
   [City] [nvarchar](100) NULL, 
   [Province] [nvarchar](100) NULL, 
   [Country] [nvarchar](100) NULL,
   PRIMARY KEY CLUSTERED ([Id] ASC) 
) 

GO 
CREATE TABLE [dbo].[Order]( 
   [Id] [uniqueidentifier] NOT NULL, 
   [CustomerId] [uniqueidentifier] NULL, 
   [Ordered] [datetime] NULL, 
   [Shipped] [datetime] NULL, 
   [Street] [nvarchar](100) NULL, 
   [City] [nvarchar](100) NULL, 
   [Province] [nvarchar](100) NULL, 
   [Country] [nvarchar](100) NULL, 
   PRIMARY KEY CLUSTERED ([Id] ASC) 
) 
GO

データベースに2つのテーブルを作成します。次の画像は、顧客テーブルを示しています。

次の画像は、顧客との外部キー関係を確認できる注文テーブルを示しています。

で接続文字列を定義する必要があります app.config ファイル、これがapp.configファイルの実装です。

<?xml version = "1.0" encoding = "utf-8" ?> 
<configuration> 
   
   <connectionStrings> 
      <add name = "default" connectionString = "Data Source =
         (localdb)\MSSQLLocalDB;Initial Catalog = NHibernateDemo;Integrated Security =
         True;Connect Timeout = 30;Encrypt = False;TrustServerCertificate = False;
         ApplicationIntent = ReadWrite;MultiSubnetFailover = False"/> 
   </connectionStrings> 

</configuration>

アプリケーションにNHibernateをインストールするには、NuGetマネージャーコンソールウィンドウで次のコマンドを実行します。

install-package NHibernate

NHibernate構成を構成するには、で構成を定義する必要があります。 hibernate.cfg.xml 次のコードに示すようにファイル。

<xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2"> 
   
   <session-factory> 
      <property name = "connection.connection_string_name">default</property>
		
      <property name = "connection.driver_class">
         NHibernate.Driver.SqlClientDriver 
      </property> 
		
      <property name = "dialect">
         NHibernate.Dialect.MsSql2008Dialect
      </property> 
		
      <property name = "show_sql">true</property> 
   </session-factory> 

</hibernate-configuration>

この例では、CustomerとOrderの2つのドメインクラスを使用します。

これは、Customer.csファイルの実装です。1つはCustomerクラスで、もう1つはObjectがCustomerクラスのアドレスとして使用されるLocationクラスです。

using System; 
using System.Text; 
using Iesi.Collections.Generic;

namespace NHibernateDemo { 

   public class Customer { 
      
      public Customer() { 
         MemberSince = DateTime.UtcNow; 
         Orders = new HashedSet<Order>(); 
      } 
      
      public virtual Guid Id { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual double AverageRating { get; set; } 
      public virtual int Points { get; set; } 
		
      public virtual bool HasGoldStatus { get; set; }
      public virtual DateTime MemberSince { get; set; } 
      public virtual CustomerCreditRating CreditRating { get; set; } 
      public virtual Location Address { get; set; }
		
      public virtual ISet<Order> Orders { get; set; }
      public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
      
      public override string ToString() { 
         var result = new StringBuilder();
			
         result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
            {4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
            {8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
            CreditRating, MemberSince.Kind, AverageRating);
            result.AppendLine("\tOrders:"); 
         
         foreach(var order in Orders) { 
            result.AppendLine("\t\t" + order); 
         } 
			
         return result.ToString(); 
      } 
   }
   
   public class Location { 
      public virtual string Street { get; set; } 
      public virtual string City { get; set; } 
      public virtual string Province { get; set; } 
      public virtual string Country { get; set; } 
   }
   
   public enum CustomerCreditRating { 
      Excellent,
      VeryVeryGood, 
      VeryGood, 
      Good, 
      Neutral, 
      Poor, 
      Terrible 
   } 
}

これがマッピングファイルです Customer.hbm.xml CustomerクラスがCustomerテーブルにマップされています。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo" 
   namespace = "NHibernateDemo"> 
	
   <class name = "Customer"> 
   
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 

      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 

   </class> 
</hibernate-mapping>

Order Classもあり、これが Order.cs ファイル。

using System; using Iesi.Collections.Generic;

namespace NHibernateDemo { 

   public class Order { 
      
      public virtual Guid Id { get; set; } 
      public virtual DateTime Ordered { get; set; } 
      public virtual DateTime? Shipped { get; set; }
      public virtual Location ShipTo { get; set; } 
      public virtual Customer Customer { get; set; }
      
      public override string ToString() { 
         return string.Format("Order Id: {0}", Id); 
      } 
   } 
}

多対1の関係

また、OrderクラスをデータベースのOrderテーブルにマップする必要があるため、次の実装を使用します。 Order.hbm.xml ファイル。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo" 
   namespace = "NHibernateDemo"> 

   <class name = "Order" table = "`Order`"> 
   
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
		
      <property name = "Ordered"/> 
      <property name = "Shipped"/> 
   
      <component name = "ShipTo"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 

      <!--<many-to-one name = "Customer" column = "CustomerId" cascade =
         "save-update"/>--> 
			
   </class> 
</hibernate-mapping>

1対多の関係

ここでは、顧客と注文の間の1対多の関係(この場合)を見ていきます。ここに顧客がいて、新しい顧客を作成しています。コレクションが次の注文のペアで初期化されていることがわかります。

private static Customer CreateCustomer() { 
   
   var customer = new Customer { 
      FirstName = "John", 
      LastName = "Doe", 
      Points = 100, 
      HasGoldStatus = true, 
      MemberSince = new DateTime(2012, 1, 1), 
      CreditRating = CustomerCreditRating.Good, 
      AverageRating = 42.42424242, 
      Address = CreateLocation() 
   }; 
   
   var order1 = new Order { 
      Ordered = DateTime.Now 
   }; 
   
   customer.AddOrder(order1); 
   var order2 = new Order { 
      Ordered = DateTime.Now.AddDays(-1), 
      Shipped = DateTime.Now, 
      ShipTo = CreateLocation() 
   }; 
   
   customer.AddOrder(order2); 
   return customer; 
}

したがって、新しい顧客を作成して保存します。保存後、IDを見つけて、次のプログラムに示すように、Mainメソッドの別のセッションで再読み込みします。

private static void Main() { 

   var cfg = ConfigureNHibernate(); 
   var sessionFactory = cfg.BuildSessionFactory();
   
   Guid id; 
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) { 
      var newCustomer = CreateCustomer(); 
      Console.WriteLine("New Customer:"); 
      Console.WriteLine(newCustomer);
      session.Save(newCustomer); 
      id = newCustomer.Id; 
      tx.Commit(); 
   }
   
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) { 
      var reloaded = session.Load<Customer>(id); 
      Console.WriteLine("Reloaded:"); 
      Console.WriteLine(reloaded); 
      tx.Commit(); 
   }
   
   Console.WriteLine("Press <ENTER> to exit..."); 
   Console.ReadLine(); 
}

これが完全です Program.cs ファイルの実装。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo {
 
   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         
         Guid id; 
         using(var session = sessionFactory.OpenSession())
			
         using(var tx = session.BeginTransaction()) { 
            var newCustomer = CreateCustomer(); 
            Console.WriteLine("New Customer:"); 
            Console.WriteLine(newCustomer); 
            session.Save(newCustomer); 
            id = newCustomer.Id; 
            tx.Commit(); 
         } 
         
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) { 
            var reloaded = session.Load<Customer>(id); 
            Console.WriteLine("Reloaded:"); 
            Console.WriteLine(reloaded); 
            tx.Commit();
         }
         
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine();
      }
      
      private static Customer CreateCustomer() { 
		
         var customer = new Customer { 
            FirstName = "John", 
            LastName = "Doe", 
            Points = 100, 
            HasGoldStatus = true, 
            MemberSince = new DateTime(2012, 1, 1), 
            CreditRating = CustomerCreditRating.Good, 
            AverageRating = 42.42424242, 
            Address = CreateLocation() 
         }; 
         
         var order1 = new Order { 
            Ordered = DateTime.Now
         }; 
         
         customer.AddOrder(order1); 
			
         var order2 = new Order { 
            Ordered = DateTime.Now.AddDays(-1), 
            Shipped = DateTime.Now, 
            ShipTo = CreateLocation() 
         }; 
         
         customer.AddOrder(order2); 
         return customer; 
      } 
      
      private static Location CreateLocation() { 
		
         return new Location { 
            Street = "123 Somewhere Avenue", 
            City = "Nowhere", 
            Province = "Alberta", 
            Country = "Canada" 
         }; 
      } 
      
      private static Configuration ConfigureNHibernate() { 
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x =&ht; { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

このアプリケーションを実行すると、次の出力が表示されます。

New Customer:

John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (9b0fcf10-83f6-4f39-bda5-a5b800ede2ba)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
Press <ENTER> to exit...

ご覧のとおり、最初は顧客に2つの注文がありますが、リロードすると、表示される注文はありません。あなたが見ればcustomer.hbm.xmlファイルを見ると、実際の注文コレクションをマッピングしていないことがわかります。したがって、NHibernateはそれについて何も知りません。先に進んで追加しましょう。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemo" namespace = "NHibernateDemo">
	
   <class name = "Customer"> 
      
      <id name = "Id">
         <generator class = "guid.comb"/> 
      </id> 
      
      <property name = "FirstName"/>
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

これはセットであり、このコレクションの名前は「Orders」であり、orderというテーブルに格納されています。外部キーの名前であるキーを指定するか、注文を見つける必要があります。これらの注文は、顧客IDを通じて識別されるか、顧客に属します。そして、これは1対多の関係であり、注文クラスとの関係であることに注意する必要があります。

また、次のプログラムに示すように、新しい顧客の注文をデータベースに保存して、Mainメソッドを少し変更する必要があります。

private static void Main() { 

   var cfg = ConfigureNHibernate(); 
   var sessionFactory = cfg.BuildSessionFactory();
   
   Guid id; 
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) {
      var newCustomer = CreateCustomer(); 
      Console.WriteLine("New Customer:"); 
      Console.WriteLine(newCustomer);
      session.Save(newCustomer); 
      
      foreach (var order in newCustomer.Orders) { 
         session.Save(order); 
      } 
		
      id = newCustomer.Id; 
      tx.Commit(); 
   }
   
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) { 
      var reloaded = session.Load<Customer>(id); 
      Console.WriteLine("The orders were ordered by: "); 
      
      foreach (var order in reloaded.Orders) { 
         Console.WriteLine(order.Customer); 
      } 
		
      tx.Commit(); 
   }
   Console.WriteLine("Press <ENTER> to exit..."); Console.ReadLine();
}

また、その特定の製品を注文した顧客も指定しました。したがって、その注文をその顧客に関連付けるには、多対1の関係を作成する必要があります。

それでは、 Order.hbm.xml ファイルを作成して多対1を追加し、顧客フィールドと列に顧客IDの名前を付けます。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
	
   <class name = "Order" table = "`Order`">
      
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id>
      
      <property name = "Ordered"/> 
      <property name = "Shipped"/> 
      
      <component name = "ShipTo"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 

      <many-to-one name = "Customer" column = "CustomerId"/> 
		
   </class> 
</hibernate-mapping>

このアプリケーションをもう一度実行すると、次の出力が表示されます。

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
      Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3

The orders were ordered by:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
      Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3

John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
      Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
		
Press <ENTER> to exit...

この章では、コレクションを表現する方法について説明します。NHibernate内で使用できるコレクションには、次のようなさまざまなタイプがあります。

  • Lists
  • Sets
  • Bags

現在、.NETの観点からは、通常、リストなど、非常に単純なデータ構造、リスト、辞書を扱います。.NETには、多種多様なコレクションタイプはありません。では、なぜNHibernateはこれらすべての異なるタイプを必要とするのでしょうか?それは本当にデータベースに戻ってきます。

リスト

  • リストは、必ずしも一意ではない要素の順序付けられたコレクションです。

  • これを使用してマッピングできます IList <T>

  • したがって、従来はアドレスのリストがあり、アプリケーションの観点からは要素が一意であることがわかっていますが、リスト内に重複する要素をそのリストに挿入することを妨げるものはありません。

セットする

  • セットは、一意の要素の順序付けられていないコレクションです。2つの重複する要素をセットに挿入しようとすると、例外がスローされます。

  • NHibernateにはそれについて具体的なことは何もありません。

  • これは、一般的なセットの実装を行うための便利な方法です。.NET 4を使用している場合は、新しいHashSet <T> これらを表すために、しかしほとんどのNHibernateアプリケーションでは、これがISetであることを表します。

  • これは順序付けされていません。データベースから住所のリストまたは注文のリストをプルバックすると、特定のOrder by句を指定しない限り、住所の順序がわかりません。

  • したがって、一般的に、データベースからプルバックするデータはセットです。

  • それらは、順序付けられていない要素のユニークなコレクションです。

バッグ

  • データベースの世界で見られるもう1つの一般的なコレクションはバッグです。これは、重複する要素を持つことができることを除けば、セットと同じです。

  • .NETの世界では、これをIListで表します。

セットがおそらく最も一般的ですが、アプリケーションに応じてリストやバッグも表示されます。以下を見てみましょうcustomer.hbm.xml セットオーダーが定義されている最後の章のファイル。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo" 
   namespace = "NHibernateDemo"> 
	
   <class name = "Customer"> 
      
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

ご覧のとおり、注文コレクションをセットとしてマッピングしました。セットは、一意の要素の順序付けられていないコレクションであることを忘れないでください。

ここで、Customerクラスを見ると、次のプログラムに示すように、OrdersプロパティがISetで定義されていることがわかります。

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

このアプリケーションを実行すると、次の出力が表示されます。

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7

The orders were ordered by:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7

John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
		
Press <ENTER> to exit...

コレクション内のアイテムが一意である必要がない場合、このコレクションで同じ主キーを使用して複数の注文が複数回発生する可能性がある場合は、次のプログラムに示すように、これをバッグとしてマッピングする方が適切です。

<bag name = "Orders" table = "`Order`"> 
   <key column = "CustomerId"/> 
   <one-to-many class = "Order"/> 
</bag>

ここで、このアプリケーションを実行すると、例外が発生します。これは、顧客クラスを見ると、注文がC#コードでISetとしてマークされていることがわかるためです。

したがって、これもIListに変更する必要があります。次に、コンストラクターでHashSetからListに変更する必要があります。

public class Customer { 
   public Customer() { 
      MemberSince = DateTime.UtcNow; 
      Orders = new List<Order>(); 
   } 
	
   public virtual Guid Id { get; set; } 
   public virtual string FirstName { get; set; } 
   public virtual string LastName { get; set; } 
   public virtual double AverageRating { get; set; } 
   public virtual int Points { get; set; } 
	
   public virtual bool HasGoldStatus { get; set; } 
   public virtual DateTime MemberSince { get; set; } 
   public virtual CustomerCreditRating CreditRating { get; set; } 
   public virtual Location Address { get; set; }
   public virtual IList<Order> Orders { get; set; }
   public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
   
   public override string ToString() { 
      var result = new StringBuilder(); 
		
      result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
         {4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
         {8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
         CreditRating, MemberSince.Kind, AverageRating); result.AppendLine("\tOrders:"); 
      
      foreach(var order in Orders) { 
         result.AppendLine("\t\t" + order); 
      } 
		
      return result.ToString(); 
   } 
}

アプリケーションを実行すると、同じ動作が見られます。しかし、今では同じコレクションで複数回注文を行うことができます。

John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287

The orders were ordered by:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287

John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
		
Press <ENTER> to exit...

この章では、カスケード機能の使用方法について説明します。アイテムのセットまたはコレクション、または顧客と注文などの2つのクラス間の関係があり、外部キー関係がある場合。デフォルトで顧客を削除した場合、NHibernateは子オブジェクトに対して何も行わないため、その顧客に属するものは、注文を孤立させる可能性があります。

  • また、外部キー制約に違反している可能性があるため、カスケードの概念を使用できます。

  • デフォルトでは、NHibernateは操作を子オブジェクトにカスケードしません。

  • これは、デフォルトの配送先住所を持つ顧客などの関係を築くことができ、配送先住所が多くの異なる顧客と共有されるためです。

  • したがって、他の顧客がまだそれを参照しているため、必ずしもその関係をカスケードする必要はありません。

  • したがって、カスケードの全体的な概念は、NHibernateにその子エンティティを処理する方法を指示することです。

カスケードにはさまざまなオプションがあり、次のとおりです。

  • none −これはデフォルトであり、カスケードがないことを意味します。

  • all −これは、保存、更新、および削除をカスケードします。

  • save-update −カスケード、保存、更新します。

  • delete −削除をカスケードします。

  • all-delete-orphan −これは非常に頻繁に使用される特別なものであり、すべてを除いて同じです。削除孤立行が見つかった場合は、それらも削除されます。

でデフォルトを指定できます hbm.xml ファイルなので、そのHibernateマッピング要素にデフォルトのカスケードを提供することも、多対1などの特定のコレクションや関係に指定することもできます。

カスケードの簡単な例を見てみましょう。プログラムの問題を修正しましょう。次のコードに示すように、保存を注文に手動でカスケードする必要があります。

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) { 
   var newCustomer = CreateCustomer(); 
   Console.WriteLine("New Customer:"); 
   Console.WriteLine(newCustomer); 
   session.Save(newCustomer); 
	
   foreach (var order in newCustomer.Orders) { 
      session.Save(order); 
   } 
	
   id = newCustomer.Id; 
   tx.Commit(); 
}

上記のコードスニペットでは、顧客のすべての注文を手動で保存していることがわかります。次に、すべての注文が保存されている手動カスケードコードを削除しましょう。

using(var session = sessionFactory.OpenSession())
 
using(var tx = session.BeginTransaction()) { 
   var newCustomer = CreateCustomer(); 
   Console.WriteLine("New Customer:"); 
   Console.WriteLine(newCustomer);
	
   session.Save(newCustomer); 
   id = newCustomer.Id; 
   tx.Commit(); 
}

でカスケードオプションを指定する必要があります customer.hbm.xml

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
	
   <class name = "Customer"> 
   
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
      
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>
  • 現在、注文は完全に顧客のものです。したがって、顧客がデータベースから削除された場合、ここでのアプリケーションは、孤立している可能性のある注文を含め、それらの注文をすべて削除する必要があります。

  • 削除を行うことになります。それによって、注文テーブルから削除と表示されます。ここで、顧客IDは、削除する顧客と同じです。

  • したがって、実際にこれらの削除をカスケードできます。だからとAll、保存、更新、削除を行います。

このアプリケーションを実行すると、次の出力が表示されます。

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134

The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134

John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
		
Press <ENTER> to exit...

ご覧のとおり、手動でカスケードされたプログラムからコードを削除しましたが、アプリケーションは引き続き機能しています。

したがって、関係によっては、それらをカスケードすることをお勧めします。それでは、別のカスケード関係を見てみましょう。に行きましょうOrder.hbm.xml ファイルを作成すると、その多対1の関係をカスケードできます。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
   
   <class name = "Order" table = "`Order`"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 

      <property name = "Ordered"/> 
      <property name = "Shipped"/> 
      
      <component name = "ShipTo"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 
      
      <many-to-one name = "Customer" column = "CustomerId" cascade = "save-update"/>
		
   </class> 
</hibernate-mapping>

したがって、新しい注文を作成し、それに添付された新しい顧客がいて、その注文を保存すると言う場合、それをカスケードすることができます。しかし、おそらくやりたくないことの1つは、注文が削除されて対応する顧客が削除された場合です。

したがって、ここでは、保存更新を実行する必要があるため、保存更新を使用すると、保存または更新がその顧客にカスケードされます。したがって、新しい顧客を獲得した場合、または顧客を変更する場合は、それをカスケードします。削除の場合、データベースから削除されません。

したがって、アプリケーションを再度実行しても、すべてが期待どおりに機能します。

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134

The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
      John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
		
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
		
Press <ENTER> to exit...

ここで、アプリケーションを確認する必要があります。デフォルトはNoneであり、エンティティとそれらの間の関係を考慮して、各エンティティとそのデータベース内の各関係に適切なカスケードを決定する必要があることを忘れないでください。

この章では、遅延読み込み機能について説明します。これはデフォルトではまったく異なる概念であり、NHibernateには遅延読み込みがありません。たとえば、顧客を読み込む場合、すべての注文が読み込まれるわけではありません。

  • 注文コレクションはオンデマンドで読み込まれます。

  • 多対1であろうとコレクションであろうと、関連付けはデフォルトで遅延読み込みされるため、 Open ISession

  • セッションを閉じた場合、またはトランザクションをコミットした場合、それらの追加オブジェクトをプルできない遅延読み込み例外が発生する可能性があります。

  • 遅延読み込みと実際に必要なデータ量に注意する必要があります。

  • アソシエーション全体の遅延読み込みをオフにするか、遅延をfalseに設定するか、フェッチ戦略を指定することもできます。

これが Program.cs ファイルの実装。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         
         Guid id; 
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) {
            var newCustomer = CreateCustomer(); 
            Console.WriteLine("New Customer:"); 
            Console.WriteLine(newCustomer); 
            session.Save(newCustomer); 
            id = newCustomer.Id; 
            tx.Commit(); 
         }
         
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) { 
            var reloaded = session.Load<Customer>(id); 
            Console.WriteLine("Reloaded:"); 
            Console.WriteLine(reloaded); 
            Console.WriteLine("The orders were ordered by: "); 
            
            foreach (var order in reloaded.Orders) { 
               Console.WriteLine(order.Customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Customer CreateCustomer() { 
         
         var customer = new Customer { 
            FirstName = "John", 
            LastName = "Doe", 
            Points =100, 
            HasGoldStatus = true, 
            MemberSince = new DateTime(2012, 1, 1),
            CreditRating = CustomerCreditRating.Good,
            AverageRating = 42.42424242, 
            Address = CreateLocation() 
         }; 
			
         var order1 = new Order { Ordered = DateTime.Now }; 
         customer.AddOrder(order1); 
         
         var order2 = new Order { 
            Ordered = DateTime.Now.AddDays(-1), 
            Shipped = DateTime.Now, 
            ShipTo = CreateLocation() 
         }; 
			
         customer.AddOrder(order2); return customer; 
      }
		
      private static Location CreateLocation() { 
         return new Location { 
            Street = "123 Somewhere Avenue", 
            City = "Nowhere", 
            Province = "Alberta", 
            Country = "Canada" 
         }; 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect<(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10;
            x.BatchSize = 10;
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

これを理解するために、アプリケーションを実行してNHibernateプロファイラーを見てみましょう。

ご覧のとおり、特定の顧客IDが指定されたSelect From Customerがあり、実際にその顧客のコレクションにアクセスすると、別のSelect FromOrdersテーブルもあります。

したがって、データベースへの往復は2回あります。さて、時々、これを最適化したいでしょう。これを行うには、に行きましょうcustomer.hbm.xml ファイルを作成し、フェッチ戦略を追加して、結合フェッチを実行するように依頼します。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
   
   <class name = "Customer"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan" 
         fetch = "join"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

アプリケーションのコードを変更していないことがわかるように、フェッチ戦略を追加しました。 customer.hbm.xml。このアプリケーションをもう一度実行してみましょう。それでもまったく同じように動作します。NHibernateプロファイラーを見てみましょう。

  • 以前は、プログラムはデータベースに2回往復していましたが、現在は1回しかありません。これは、ここで左外部結合を実行しているためです。

  • 顧客IDに基づいて、顧客テーブルと注文テーブルの間で左外部結合を実行していることがわかります。したがって、すべての情報を一度にロードできます。

  • データベースへの往復を1回保存しました。

  • 欠点は、顧客情報が両方の行に複製されることです。これが、SQLの左外部結合が機能する方法です。

  • したがって、フェッチ戦略を使用すると、もう少しデータをプルバックし、ラウンドトリップを節約できます。

これはクエリレベルでも実行できるので、 Program.cs ファイルを作成し、リロードされたより単純な例を見てください。

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) { 
   //var query = from customer in session.Query<Customer>() 
   // select customer; 
   //var reloaded = query.Fetch(x => x.Orders).ToList();
	
   var reloaded = session.Load<Customer>(id); 
   Console.WriteLine("Reloaded:"); 
   Console.WriteLine(reloaded); 
   Console.WriteLine("The orders were ordered by: "); 
   
   foreach (var order in reloaded.Orders) { 
      Console.WriteLine(order.Customer); 
   } 
	
   tx.Commit(); 
}

ここでは、お客様によるロードを行っています。それをクエリに変更してみましょう。次のコードに示すように、リンククエリを使用します。

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) {
   var query = from customer in session.Query<Customer>() 
   where customer.Id == id select customer; 
   var reloaded = query.Fetch(x => x.Orders).ToList().First();
	
   Console.WriteLine("Reloaded:"); 
   Console.WriteLine(reloaded); 
	
   tx.Commit();
}

からフェッチ戦略も削除しましょう customer.hbm.xml ファイル。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 

   <class name = "Customer"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/>
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
   
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
   
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

このアプリケーションをもう一度実行すると、次の出力が表示されます。

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (6ebacd17-f9ba-4ad8-9817-a5bb01112a5a)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 16a6596b-d56e-41c7-9681-a5bb01112a60
      Order Id: d41d615b-0f21-4032-81db-a5bb01112a61
		
Press <ENTER> to exit...

NHibernateプロファイラーを見てみましょう。この熱心な結合フェッチが再び発生していることがわかりますが、今回はクエリに基づいています。

この章では、逆の関係である別の機能について説明します。これは、コレクションに表示される、trueに反比例する面白いオプションであり、多くの開発者を混乱させます。それでは、このオプションについて話しましょう。これを理解するには、本当にリレーショナルモデルについて考える必要があります。単一の外部キーを使用した双方向の関連付けがあるとします。

  • リレーショナルの観点からは、1つの外部キーがあり、注文する顧客と顧客への注文の両方を表します。

  • OOモデルから、これらの参照を使用した単方向の関連付けがあります。

  • 2つの単方向の関連付けがデータベース内の同じ双方向の関連付けを表すと言っていることは何もありません。

  • ここでの問題は、NHibernateがそれを知るのに十分な情報を持っていないということです customer.orders そして order.customer データベース内の同じ関係を表します。

  • 提供する必要があります inverse equals true ヒントとして、これは単方向の関連付けが同じデータを使用しているためです。

  • 2つの参照を持つこれらの関係を保存しようとすると、NHibernateはその参照を2回更新しようとします。

  • 実際には、データベースへの追加のラウンドトリップを実行し、その外部キーに対して2つの更新も行います。

  • 逆がtrueに等しい場合、NHibernateは関係のどちら側を無視するかを指示します。

  • これをコレクション側に適用すると、NHibernateは常に反対側から、子オブジェクト側から外部キーを更新します。

  • その場合、その外部キーに対する更新は1つだけであり、そのデータに対する追加の更新はありません。

  • これにより、外部キーに対するこれらの重複更新を防ぐことができ、外部キー違反を防ぐこともできます。

見てみましょう customer.cs あなたが見るファイル AddOrderここでの方法と考え方は、注文から顧客へのこのバックポインターがあり、設定する必要があるということです。したがって、注文が顧客に追加されると、その顧客のバックポインターが設定されます。そうでない場合は、nullになります。したがって、オブジェクトグラフでこれを適切に接続し続けるには、これが必要です。

using System; 
using System.Text; 
using Iesi.Collections.Generic;

namespace NHibernateDemo {
 
   public class Customer { 
      
      public Customer() {
         MemberSince = DateTime.UtcNow; Orders = new HashedSet<Order>();
      } 
      
      public virtual Guid Id { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual double AverageRating { get; set; } 
      public virtual int Points { get; set; } 
      public virtual bool HasGoldStatus { get; set; } 
		
      public virtual DateTime MemberSince { get; set; } 
      public virtual CustomerCreditRating CreditRating { get; set; } 
      public virtual Location Address { get; set; }
      public virtual ISet<Order> Orders { get; set; }
      public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
      
      public override string ToString() { 
         var result = new StringBuilder(); 
			
         result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
            {4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
            {8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
            CreditRating, MemberSince.Kind, AverageRating);
         result.AppendLine("\tOrders:"); 
         
         foreach(var order in Orders) { 
            result.AppendLine("\t\t" + order); 
         } 
			
         return result.ToString(); 
      } 
   }
   
   public class Location { 
      public virtual string Street { get; set; } 
      public virtual string City { get; set; } 
      public virtual string Province { get; set; } 
      public virtual string Country { get; set; }
   } 
   
   public enum CustomerCreditRating { 
      Excellent, 
      VeryVeryGood, 
      VeryGood, 
      Good, 
      Neutral, 
      Poor, 
      Terrible 
   } 
}

これが Program.cs ファイルの実装。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         Guid id; 
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var newCustomer = CreateCustomer(); 
            Console.WriteLine("New Customer:"); 
            Console.WriteLine(newCustomer); 
            session.Save(newCustomer); 
            id = newCustomer.Id;
            tx.Commit(); 
         }
         
         using(var session = sessionFactory.OpenSession())

         using(var tx = session.BeginTransaction()) { 
            var query = from customer in session.Query<Customer>() where
               customer.Id == id select customer; 
					
            var reloaded = query.Fetch(x => x.Orders).ToList().First();
            Console.WriteLine("Reloaded:"); Console.WriteLine(reloaded); 

            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
      
      private static Customer CreateCustomer() { 
         var customer = new Customer { 
            FirstName = "John", 
            LastName = "Doe", 
            Points = 100, 
            HasGoldStatus = true, 
            MemberSince = new DateTime(2012, 1, 1), 
            CreditRating = CustomerCreditRating.Good, 
            AverageRating = 42.42424242, 
            Address = CreateLocation() 
         }; 
			
         var order1 = new Order { Ordered = DateTime.Now }; 
         
         customer.AddOrder(order1); var order2 = new Order {
            Ordered = DateTime.Now.AddDays(-1), 
            Shipped = DateTime.Now, 
            ShipTo = CreateLocation()
         }; 
			
         customer.AddOrder(order2); 
         return customer; 
      }
      
      private static Location CreateLocation() { 
         return new Location { 
            Street = "123 Somewhere Avenue", 
            City = "Nowhere", 
            Province = "Alberta", 
            Country = "Canada" 
         }; 
      }
      
      private static Configuration ConfigureNHibernate() { 
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

それをデータベースに保存してからリロードします。次に、アプリケーションを実行してNHibernate Profilerを開き、実際にどのように保存されたかを確認しましょう。

3つのグループのステートメントがあることに気付くでしょう。最初のものは顧客を挿入し、その顧客のIDはGuidであり、強調表示されます。2番目のステートメントはordersテーブルに挿入されます。

同じCustomerId Guidが設定されていることに気付くので、その外部キーを設定します。最後のステートメントは更新です。これにより、外部キーが同じ顧客IDに再度更新されます。

ここで問題となるのは、顧客が注文を持っており、注文に顧客がいるということです。NHibernateに実際には同じ関係であると伝えていない方法はありません。これを行う方法は、inverse equalstrueを使用することです。

だから私たちに行きましょう customer.hbm.xml 次のコードに示すように、ファイルをマッピングし、逆数をtrueに設定します。

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
   
   <class name = "Customer">
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
      
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/>
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan" 
         inverse = "true"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

注文を保存するときに、注文側からその外部キーを設定します。次に、このアプリケーションを再度実行して、NHibernateプロファイラーを開きます。

それらがどのように挿入されるかを見ると、顧客に挿入され、注文に挿入されますが、注文が保存されるときに更新されるため、外部キーの重複した更新はありません。

  • ここで、単方向の関連付けのみがあり、この関係を維持しているのがセットである場合、inverse equals trueを回すと、その外部キーが設定されることはなく、それらのアイテムにそれらのアイテムが含まれることはないことに注意してください。データベースに設定された外部キー。

  • あなたがの多対一の関係を見れば Order.hbm.xml ファイルとあなたが逆を探す、それは実際には逆属性を持っていません。

  • 常に子アイテムから設定されますが、多対多のコレクションがある場合は、どちらの側からでも設定できます。

この章では、ロード機能と取得機能がどのように機能し、どのように使用できるかについて説明します。これらは、によって提供される2つの非常に類似したAPIです。ISession 主キーでオブジェクトをロードするため。

  • Get −オブジェクトまたはnullを返します。

  • Load −オブジェクトを返すか、をスローします ObjectNotFoundException

では、なぜこれら2つの異なるAPIがあるのでしょうか。

負荷

  • これは、Loadがデータベースのラウンドトリップをはるかに効率的に最適化できるためです。

  • Loadは実際にはプロキシオブジェクトを返し、Load呼び出しを発行したときにデータベースに直接アクセスする必要はありません。

  • そのプロキシにアクセスすると、オブジェクトがデータベースに存在することはなく、その時点でObjectNotFoundExceptionがスローされる可能性があります。

取得する

  • 逆に、CLRの制限のためにGetを使用するか、 Common Language Runtime NHibernateはすぐにデータベースにアクセスし、オブジェクトが存在するかどうかを確認し、存在しない場合はnullを返す必要があります。

  • プロキシオブジェクトを返すことができず、ユーザーが実際にアクセスしたときにそのプロキシオブジェクトをnullにスワップアウトするため、そのフェッチ、データベースへのラウンドトリップを遅らせるオブジェクトオプションはありません。

これらが実際にどのように使用されているか、およびGetとLoadの違いを確認する簡単な例を見てみましょう。同じドメインクラスを継続しますCustomers そして Orders 同様に、前の章と同じマッピングファイル。

この例では、次のプログラムに示すように、最初にGetを使用します。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver;
using NHibernate.Linq; 

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be"); 
            var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
				
            var customer1 = session.Get<Customer>(id1); 
            Console.WriteLine("Customer1 data"); 
            Console.WriteLine(customer1);
				
            var customer2 = session.Get<Customer>(id2); 
            Console.WriteLine("Customer2 data"); 
            Console.WriteLine(customer2); 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead;
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

ご覧のとおり、2つあります GuidID、最初のIDは適切なIDであり、データベースにあることがわかっている顧客のIDです。2番目のIDがデータベースに存在しない間。これらのIDは両方ともパラメータとしてに渡されますGet() メソッドを実行すると、結果がコンソールに出力されます。

上記のコードをコンパイルして実行すると、次の出力が表示されます。

Customer1 data
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

Orders:
   Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
   Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
   Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
   Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
	
Customer2 data
Press <ENTER> to exit...

ご覧のとおり、Customer1データは印刷されていますが、Customer2データは空です。これは、Customer2レコードがデータベースで使用できないためです。

アプリケーションを再度実行すると、commitステートメントの前にブレークポイントを挿入して、[ウォッチ]ウィンドウで両方の顧客を確認できます。

ご覧のとおり、Customer1データは利用可能ですが、Customer2はnullで、タイプは NHibernateDemo.Customer 両方のための。

次のコードに示すのと同じ例で、Getの代わりにLoadメソッドを使用してみましょう。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver;
using NHibernate.Linq; 

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be"); 
            var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
				
            var customer1 = session.Load<Customer>(id1); 
            Console.WriteLine("Customer1 data"); 
            Console.WriteLine(customer1);
				
            var customer2 = session.Load<Customer>(id2); 
            Console.WriteLine("Customer2 data"); 
            Console.WriteLine(customer2); 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10;
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

この例を実行してみましょう。スクリーンショットに示すように、次の例外がスローされることがわかります。

ここで、[ウォッチ]ウィンドウを見ると、タイプが両方のオブジェクトのカスタマープロキシであることがわかります。また、コンソールウィンドウにCustomer1の同じデータが表示されます。

Customer1 data
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be 
		
Customer2 data

この章では、人々が使用するもう1つの一般的なAPIであるNHibernateLINQプロバイダーについて説明します。ISessionの拡張メソッドを介したアクセスと署名はQuery <T>。LINQを使用する場合の構文には2つのタイプがあります-

  • クエリ連鎖構文
  • クエリ理解構文

クエリ連鎖構文

次のプログラムに示すように、メソッドチェーン構文を使用してデータベースから任意のレコードにアクセスできます。

var customer = session.Query<Customer>() .Where(c => c.FirstName == "Laverne")
  • クエリとWHERE句があり、追加のWHERE句と同様にselect句を使用できることがわかります。

  • これは、通常のLINQで使用できる標準のメソッドチェーン構文です。

  • LINQ toObjectsまたはLINQto SQL、おなじみのその他のLINQプロバイダー。

Laverneという名の顧客を取得する簡単な例を見てみましょう。現在、名がLaverneである顧客が複数存在する可能性があるため、最初の顧客のみを取得します。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program {
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customer = session.Query<Customer>() 
               .Where(c => c.FirstName == "Laverne").First(); 
            Console.WriteLine(customer); 
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

上記のコードをコンパイルして実行すると、次の出力が表示されます。

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

クエリ理解構文

クエリ内包表記の構文もあります。これは、from、where、およびselectキーワードを使用したSQLによく似ています。

同じ例を見てみましょうが、今回はLINQ内包表記を使用します。これは、次のプログラムに示すように、SQLに非常によく似ています。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customer = (from c in session.Query<Customer>() 
               where c.FirstName == "Laverne" select c).First();
            Console.WriteLine(customer); 
            tx.Commit();
         }
         
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
      
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

このアプリケーションをもう一度実行すると、次の出力が表示されます。

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

FirstNameが文字Hで始まるすべての顧客を取得する別の例を見てみましょう。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customers = session.Query<Customer>() .Where(c =<
               c.FirstName.StartsWith("H"));
            
            foreach (var customer in customers.ToList()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

同様に、クエリ内包構文は次のプログラムのようになります。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customers = from c in session.Query<Customer>() 
               where c.FirstName.StartsWith("H") select c;
            
            foreach (var customer in customers.ToList()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   }  
}

このアプリケーションをもう一度実行すると、名前がアルファベットHで始まるすべての顧客が表示されます。

Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 12/3/2010 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be

Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
   Points: 56
   HasGoldStatus: False
   MemberSince: 10/20/2008 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be

Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
   Points: 82
   HasGoldStatus: False
   MemberSince: 4/10/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
		
Press <ENTER> to exit...

この章では、Hibernateクエリ言語について説明します。HQLは、JavaのHibernateとNHibernateの両方で共有されます。

  • これは、最も古いクエリメカニズムです。 Criteria

  • それは非常に早く実装され、文字列ベースのクエリです API

  • あなたはそれを通してアクセスします ISession CreateQuery、SQLとほぼ同じです。

  • 同じキーワードの多くを使用しますが、構文は単純化されています。

  • これは最も一般的な例の1つであり、クエリの実行方法を探している場合は、HQLの例がよく見られます。

以下はHQLの簡単な例です-

var customers = session.CreateQuery("select c from Customer c where c.FirstName = 'Laverne'");
  • したがって、ここでは、顧客からCを選択していることがわかります。これは、SQLによく似ています。NHibernateに関する限り、これは不透明な文字列であるため、実行時までこれが有効なHQLであるかどうかがわかりません。これは、欠点の1つです。

  • LINQプロバイダーの強みの1つは、コンパイル時のサポートを利用できることです。

  • しかし、HQLは、よく使用される最も柔軟なクエリメカニズムの1つです。それを行う方法が他にない場合は、HQLでそれを行う方法があると言われています。

代わりにHQLを使用してLINQクエリを再作成する簡単な例を見てみましょう。HQLにアクセスするには、session.CreateQuery HQL文字列を使用してパラメータとして渡します。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo {

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateQuery("select c from Customer c 
               where c.FirstName = 'Laverne'"); 
            
            foreach (var customer in customers.List<Customer>()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}
  • このHQL文字列はSQLによく似ていますが、主な違いは、FirstNameがプロパティ名であり、列名ではないことです。

  • したがって、2つの間に不一致がある場合は、プロパティ名を使用します。同じことですが、テーブル名のように見えますが、実際には選択しているクラスの名前です。

  • バックエンドテーブルの名前がCustomersの場合でも、HQLクエリではCustomerを使用します。

このアプリケーションを実行すると、次の出力が表示されます。

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

HQLを使用して、FirstNameが文字Hで始まるすべての顧客を取得する別の簡単な例を見てみましょう。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver;
using NHibernate.Linq; 

namespace NHibernateDemo { 

   internal class Program {
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateQuery("select c from Customer c 
               where c.FirstName like 'H%'"); 
            
            foreach (var customer in customers.List<Customer>()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         } 
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      } 
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

アプリケーションを再度実行すると、名前がHで始まるすべての顧客がこのクエリから返されることがわかります。

Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 12/3/2010 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be

Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
   Points: 56
   HasGoldStatus: False
   MemberSince: 10/20/2008 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be

Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
   Points: 82
   HasGoldStatus: False
   MemberSince: 4/10/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
		
Press <ENTER> to exit...

注文数が9を超える顧客のすべての注文を希望するなど、より複雑なことを行うことができます。以下は、同じものに対するHQLクエリです。

var customers = session.CreateQuery("select c from Customer c 
   where size(c.Orders) > 9"); 
	
foreach (var customer in customers.List<Customer>()) { 
   Console.WriteLine(customer); 
}

また、ここでサイズ、カウント、または長さが必要であることを示す必要があります。HQLでは、上記のように特別なサイズの方法を使用するオプションがあります。

あなたが望むなら、これを書く他の方法は c.Orders.size、そしてこれは正確な効果があります。

var customers = session.CreateQuery("select c from Customer c 
   where c.Orders.size > 9"); 
	
foreach (var customer in customers.List<Customer>()) { 
   Console.WriteLine(customer); 
}

このアプリケーションを実行してみましょう。

Lindsay Towne (4ea3aef6-6bce-11e1-b0cb-6cf049ee52be)
   Points: 50
   HasGoldStatus: False
   MemberSince: 4/13/2007 12:00:00 AM (Utc)
   CreditRating: VeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ea3aef6-6bce-11e1-b0cc-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0cd-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0ce-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0cf-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d0-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d1-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d2-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d3-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d4-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d5-6cf049ee52be

Wyman Hammes (4ea61056-6bce-11e1-b0e2-6cf049ee52be)
   Points: 32
   HasGoldStatus: False
   MemberSince: 2/5/2011 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 0

   Orders:
      Order Id: 4ea61056-6bce-11e1-b0e3-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e4-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e5-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e6-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e7-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e8-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e9-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0ea-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0eb-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0ec-6cf049ee52be
		
Press <ENTER> to exit...

9件を超える注文があるすべての顧客がデータベースから取得されていることがわかります。

この章では、基準クエリメカニズムについて説明します。ザ・NHibernate Query by Criteria API 実行時に条件オブジェクトを操作してクエリを作成できます。

  • このアプローチでは、文字列を直接操作せずに制約を動的に指定できますが、HQLの柔軟性や能力をあまり失うことはありません。

  • 一方、基準として表現されたクエリは、HQLで表現されたクエリよりも読みにくいことがよくあります。

  • 古典的な基準構文は、次のプログラムに示すように、オブジェクトベースのクエリAPIです。

var customers = session.CreateCriteria<Customer>().Add(Restrictions.Like("FirstName", "H%"));
  • ご覧のとおり、顧客に対してセッション作成基準を実行しており、そのクエリに制限オブジェクトを追加しています。

  • これは、ユーザーが特定のオプションを選択できるが他のオプションは選択できないクエリページに役立ちます。

  • WHERE句でANDまたはORを使用できるHQLやLINQよりも、クエリ構造のようなツリーのようなものとしてクエリを構築する方が簡単です。

  • これらの基準オブジェクトを使用して、追加の制限を追加する方が簡単です。

クエリを作成し、を介して条件APIにアクセスする簡単な例を見てみましょう。 createCriteria 次に、名がHで始まるという制限を追加します。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq; 

namespace NHibernateDemo {

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateCriteria<Customer>() 
               .Add(Restrictions.Like("FirstName", "H%")); 
         
            foreach (var customer in customers.List<Customer>()) { 
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      } 
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

上記のコードをコンパイルして実行すると、次の出力が表示されます。

Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 12/3/2010 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be

Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
   Points: 56
   HasGoldStatus: False
   MemberSince: 10/20/2008 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be

Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
   Points: 82
   HasGoldStatus: False
   MemberSince: 4/10/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
		
Press <ENTER> to exit…

名が「Laverne」に等しい顧客を取得する別の簡単な例を見てみましょう。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateCriteria<Customer>() 
               .Add(Restrictions.Eq("FirstName", "Laverne")) .List<Customer>(); 
            
            foreach (var customer in customers) {
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

このアプリケーションをもう一度実行すると、次の出力が表示されます。

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

現在、基準APIの主な欠点の1つは、プロパティ名のこれらの不透明な文字列です。したがって、名が別の名前にリファクタリングされた場合、リファクタリングツールは必ずしも不透明な文字列を取得するとは限りません。

この章では、QueryOverクエリについて説明します。これは、次のクエリに示すように、メソッドチェーン構文を使用するLINQに似た新しい構文です。

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "Laverne");
  • それはまだ隠された基準ですが、今ではクエリは強く型付けされています。

  • 条件クエリで見たように、名は不透明な文字列ですが、実際には x.FirstName、したがって、名はリファクタリングされ、名前が変更されます。これは、クエリを使用したリンクスタイル基準クエリで変更されます。

  • まだ多くの同様のことを行うことができますが、クエリオーバーでクエリ理解構文を使用することはできません。メソッドチェーン構文を使用する必要があり、リンクと条件を組み合わせて一致させることはできません。

  • 多くのクエリでは、APIを介したクエリは非常に便利であり、Criteriaを直接使用するよりもはるかに簡単にオブジェクトの構文を理解できます。

クエリを使用して、名がLaverneである顧客を取得する簡単な例を見てみましょう。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.QueryOver<Customer>() 
               .Where(x => x.FirstName == "Laverne"); 
            
            foreach (var customer in customers.List()) { 
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
      
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize();
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         });
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

ご覧のとおり、これはまだカバーの下の基準ですが、より優れた構文です。

上記のコードをコンパイルして実行すると、次の出力が表示されます。

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

欠点の1つは、それを言いたいとしましょう。 FirstName.StartsWith(“A”) 次のプログラムに示すように。

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName.StartsWith("A"));
 
foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
} 

tx.Commit();

ここでアプリケーションを再度実行してみましょう。これが何であるかがわからないため、これはLINQプロバイダーではないことがわかります。 StartsWith メソッドは、だからあなたは得るでしょう RunTime exception

例外は、認識されないメソッド呼び出しを示しています。ここでは明らかなことを行っていますが、必ずしも機能するとは限りません。

次のコードに示すように、FirstNameが「A%」に等しいなど、別のことを試してみましょう。

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "A%"); 

foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
}

これをもう一度実行してみましょう。以下に示すように、結果が返されないことがわかります。

Press <ENTER> to exit...

結果が得られない理由を理解するために、NHibernateプロファイラーを見てみましょう。

ご覧のとおり、名はA%と同じですが、そうではありません。%は、SQLでlike演算子を使用して使用されます。次に、次のプログラムに示すように、WHERE句に制限を作成する必要があります。

var customers = session.QueryOver<Customer>() 
   .Where(Restrictions.On<Customer>(c => c.FirstName).IsLike("A%")); 
	
foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
}

アプリケーションを再度実行すると、すべての顧客がAで始まる名で取得されていることがわかります。

Alejandrin Will (4ea3aef6-6bce-11e1-b0b4-6cf049ee52be)
   Points: 24
   HasGoldStatus: False
   MemberSince: 10/1/2011 12:00:00 AM (Utc)
   CreditRating: VeryVeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ea3aef6-6bce-11e1-b0b5-6cf049ee52be

Austyn Nolan (4ea871b6-6bce-11e1-b110-6cf049ee52be)
   Points: 67
   HasGoldStatus: True
   MemberSince: 12/29/2007 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea871b6-6bce-11e1-b111-6cf049ee52be

Antonia Murphy (4ea871b6-6bce-11e1-b121-6cf049ee52be)
   Points: 72
   HasGoldStatus: True
   MemberSince: 6/15/2009 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ea871b6-6bce-11e1-b122-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b123-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b124-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b125-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b126-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b127-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b128-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b129-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b12a-6cf049ee52be

この新しいものを使用することを除いて、以前と同じように機能します QueryOver構文。多くの開発者は、LINQ構文の方が親しみやすく、正しいことを行うことが多いと感じています。

LINQで処理できない場合は、HQLまたはCriteriaを調べて、それがより適切かどうかを確認します。

構文が異なるだけなので、Criteriaは、作成基準とQueryOverの両方で、NHibernateを使用してデータベースからデータを引き出すことができるさらに別のクエリメカニズムを提供します。

この章では、NHibernateでネイティブSQLクエリを使用する方法について説明します。手書きのSQLを何年も使用している場合は、ORMによって使い慣れた表現力と柔軟性が失われるのではないかと心配するかもしれません。

  • NHibernateの強力なクエリ機能を使用すると、SQLで行うほとんどすべてのことを実行でき、場合によってはそれ以上のことも実行できます。

  • NHibernate独自のクエリ機能を正確に実行させることができないまれなケースです。

  • NHibernateを使用すると、データベースのネイティブSQLダイアレクトを使用してオブジェクトを取得できます。

NHibernateのネイティブSQLクエリの簡単な例を見てみましょう。

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq; 
using NHibernate;

namespace NHibernateDemo {

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            IQuery sqlQuery = session.CreateSQLQuery("SELECT * FROM
               CUSTOMER").AddEntity(typeof(Customer));
            var customers = sqlQuery.List<Customer>();
				
            foreach (var customer in customers) { 
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
         
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

上記の例では CreateSQLQuery() オブジェクトのリストを取得します。また、クエリで返すルートエンティティタイプがCustomerとして指定されていることにも気付くでしょう。

アプリケーションを実行してみましょう。すべての顧客がデータベースから取得されていることがわかります。

Emerson Prosacco (4ec2a0e0-6bce-11e1-b2cf-6cf049ee52be)
   Points: 17
   HasGoldStatus: False
   MemberSince: 6/22/2007 12:00:00 AM (Utc)
   CreditRating: Excellent
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2d0-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d1-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d2-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d3-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d4-6cf049ee52be

Kaci Friesen (4ec2a0e0-6bce-11e1-b2d5-6cf049ee52be)
   Points: 30
   HasGoldStatus: True
   MemberSince: 5/25/2007 12:00:00 AM (Utc)
   CreditRating: VeryVeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2d6-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d7-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d8-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d9-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2da-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2db-6cf049ee52be

Eveline Waters (4ec2a0e0-6bce-11e1-b2dc-6cf049ee52be)
   Points: 58
   HasGoldStatus: False
   MemberSince: 10/29/2009 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2dd-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2de-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2df-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e0-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e2-6cf049ee52be

Molly Kuhn (4ec2a0e0-6bce-11e1-b2e3-6cf049ee52be)
   Points: 73
   HasGoldStatus: False
   MemberSince: 12/16/2007 12:00:00 AM (Utc)
   CreditRating: VeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2e4-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e5-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e6-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e7-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e8-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e9-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2ea-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2eb-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2ec-6cf049ee52be

以下に示すように、ネイティブSQLクエリを作成する別の方法を次に示します。

IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER")
   .AddScalar("Id", NHibernateUtil.Guid) 
   .AddScalar("FirstName", NHibernateUtil.String) 
   .AddScalar("LastName", NHibernateUtil.String) .List<Customer>();
  • ご覧のとおり、上記のクエリでは、SQLクエリ文字列と返される列とタイプが指定されています。

  • これにより、Customerテーブルの各列のスカラー値を持つオブジェクト配列のIListが返されます。

  • クエリが*を使用していて、リストされている3つ以上の列を返す可能性がある場合でも、これらの3つの列のみが返されます。

別の簡単な例を見てみましょう。

IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER WHERE  
   FirstName = 'Laverne'") 
   .AddEntity(typeof(Customer)) .List<Customer>(); 
	
foreach (var customer in customers) { 
   Console.WriteLine(customer); 
}

アプリケーションを再度実行すると、次の出力が表示されます。

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

同様に、任意のタイプのSQLクエリを指定して、データベースからデータを取得できます。

この章では、流暢なNHibernateについて説明します。Fluent NHibernateはマッピングの別の方法であるか、NHibernateの標準XMLマッピングファイルの代替であると言えます。XMLを書く代わりに(.hbm.xml files)ドキュメント。Fluent NHibernateを使用すると、強く型付けされたC#コードでマッピングを記述できます。

  • Fluent NHibernateでは、マッピングはアプリケーションの残りの部分と一緒にコンパイルされます。

  • アプリケーションコードと同じようにマッピングを簡単に変更でき、コンパイラはタイプミスで失敗します。

  • 従来の構成システムがあり、命名規則やその他の多くのものをオーバーライドするためのパターンを指定できます。

  • 一度名前を付ける方法を設定することもできます。その後、FluentNHibernateが残りの名前を付けます。

新しいコンソールプロジェクトを作成して、簡単な例を見てみましょう。この章では、次の図に示すような単純なCustomerテーブルを持つ単純なデータベースを使用します。

FluentNHibernateをインストールします

最初のステップはFluentNHibernateを開始することです。FluentNHibernateパッケージをインストールすることです。だから開いてNuGet Package Manager Console 次のコマンドを入力します。

PM> install-package FluentNHibernate

正常にインストールされると、次のメッセージが表示されます。

Customerの単純なモデルクラスを追加してみましょう。次のプログラムは、Customerクラスの実装を示しています。

using System; 
using System.Collections.Generic; 
using System.Linq;
using System.Text; 
using System.Threading.Tasks;

namespace FluentNHibernateDemo { 
   class Customer { 
      public virtual int Id { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual string LastName { get; set; } 
   } 
}

次に、流暢なNHibernateを使用してマッピングを作成する必要があるため、クラスをもう1つ追加します。 CustomerMapあなたのプロジェクトで。これがCustomerMapクラスの実装です。

using FluentNHibernate.Mapping; 
using System; 
using System.Collections.Generic; 
using System.Linq; using System.Text; 
using System.Threading.Tasks;

namespace FluentNHibernateDemo { 
   class CustomerMap : ClassMap<Customer> { 
      public CustomerMap() { 
         Id(x => x.Id); 
         Map(x => x.FirstName); 
         Map(x => x.LastName); 
         Table("Customer"); 
      } 
   }
}

別のクラスを追加しましょう NHibernateHelper ここで、さまざまな構成設定を設定します。

using FluentNHibernate.Cfg; 
using FluentNHibernate.Cfg.Db; 
using NHibernate; 
using NHibernate.Tool.hbm2ddl;

namespace FluentNHibernateDemo { 

   public class NHibernateHelper { 
	
      private static ISessionFactory _sessionFactory;
		
      private static ISessionFactory SessionFactory { 
         get { 
            if (_sessionFactory == null)
            InitializeSessionFactory(); return _sessionFactory; 
         } 
      }
   
      private static void InitializeSessionFactory() { 
         _sessionFactory = Fluently.Configure() 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         .Database(MsSqlConfiguration.MsSql2008 .ConnectionString( 
            @"Data Source + Initial Catalog + Integrated Security + Connect Timeout
            + Encrypt + TrustServerCertificate + ApplicationIntent + 
            MultiSubnetFailover") .ShowSql() ) 
				
         .Mappings(m => m.FluentMappings
         .AddFromAssemblyOf<Program>()) 
         .ExposeConfiguration(cfg => new SchemaExport(cfg) 
         .Create(true, true)) 
         .BuildSessionFactory(); 
      }
		
      public static ISession OpenSession() { 
         return SessionFactory.OpenSession(); 
      } 
   }
}

それでは、に移動しましょう Program.cs 以下に示すように、セッションを開始してから新しい顧客を作成し、その顧客をデータベースに保存するファイル。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace FluentNHibernateDemo { 
   class Program { 
	
      static void Main(string[] args) { 
		
         using (var session = NHibernateHelper.OpenSession()) { 
			
            using (var transaction = session.BeginTransaction()) { 
               var customer = new Customer { 
                  FirstName = "Allan", 
                  LastName = "Bomer" 
               }; 
					
               session.Save(customer); 
               transaction.Commit();
               Console.WriteLine("Customer Created: " + customer.FirstName + "\t" +
                  customer.LastName); 
            } 
				
            Console.ReadKey(); 
         } 
      } 
   } 
}

アプリケーションを実行すると、次の出力が表示されます。

if exists (select * from dbo.sysobjects where id = object_id(N'Customer') and
   OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Customer

create table Customer (
   Id INT IDENTITY NOT NULL,
   FirstName NVARCHAR(255) null,
   LastName NVARCHAR(255) null,
   primary key (Id)
)

NHibernate: INSERT INTO Customer (FirstName, LastName) VALUES (@p0, @p1); 
   select SCOPE_IDENTITY();@p0 = 'Allan' [Type: String (4000)], 
   @p1 = 'Bomer' [Type: String (4000)]
   Customer Created: Allan Bomer

ご覧のとおり、新しい顧客が作成されています。顧客レコードを表示するには、データベースに移動してデータの表示を確認すると、1人の顧客が追加されていることがわかります。