Nhibernate:マッピングオプション、クエリオプション

この記事では、私が定期的にアクセスするすべての情報をまとめて、インターネットまたはコードで探し回ることにしました。 これらは、NHibernateのマッピングとリンクです。 メモ記事のようなものになります。 過度に書き過ぎないように決めました(たとえば、NHibernate Queriesについてはほとんど書きませんでした)。したがって、各見出しには、メモ記事の作成時に依存した記事(英語)へのリンクがあります。 彼女があなたの役に立つことを願っています。


ASP.NET MVC 4とSQL Server 2008の例を示します(ところで、後者にアクセスすることはほとんどありません。データの保存方法を確認するだけですが、接続文字列に言及しています)。 具体的かつ簡潔に記述しようとします。理解できない瞬間がある場合は、ASP.NET MVCとSQL Serverを使用したFluentNHibernateのレッスンの記事をお願いします。 すべてがより詳細に説明されているパート1 。 それでは、始めましょう、Visual Studioを起動して:
  1. 新規プロジェクトFile-> New-> Projectを作成します。
  2. ASP.NET MVC 4(.Net Framework 4)を選択し、 NHibernateMVCと呼びます。
  3. Modelsフォルダーで、NHibernateフォルダーを作成します。
  4. パッケージマネージャーコンソールで、 インストールパッケージnhibernateを記述します (以下の例はFluentNhibernateでも動作します(検証済み!):インストールパッケージFluentnhibernate)。


Nhibernateをインストールした後、アプリケーションのクラスをデータベースのテーブルに関連付ける(マップする)方法に関して疑問が生じます。 NHibernateには、次のような3種類のマッピングがあります。


マッピングオプション。
1.XMLファイル

開発されたマッピングの最初。
長所:
+インターネットには多くの例があります。
+他のすべてのメソッド(属性およびFluent)は、これらのxmlファイルを受信するように削減されます。
短所:
-インテリセンスが完全に欠落しています(!)。
-コンパイル時の検証はありません。

それでは、それを見てみましょう。
NHibernateをインストールした後、Nhibernate.cfg.xmlファイルをModels-> NHibernateフォルダーに追加します
<?xml version="1.0" encoding="utf-8" ?> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="connection.provider"> NHibernate.Connection.DriverConnectionProvider </property> <property name="connection.driver_class"> NHibernate.Driver.SqlClientDriver </property> <property name="connection.connection_string"> Server=...\SQLENTERPRISE; database=NhibernateTutor; Integrated Security=SSPI; </property> <property name="dialect"> NHibernate.Dialect.MsSql2008Dialect </property> </session-factory> </hibernate-configuration> 

私はSQL Serverを使用しているため、SqlClientDriverを選択しました。 別のデータベースを使用している場合は、NHibernate.DriverのリストはここでNHibernate.Driverにあります。
私はSQL Server 2008を持っているので、MsSql2008Dialectを選択しました。すべての方言はここで表示できますSQL方言
SQL ServerでNhibernateTutorデータベースを作成し、接続文字列を記述します。 この記事では、テーブルを作成せず、NHibernate自体がテーブルを生成します。

次に、Books.csクラスをModelsフォルダーに追加します。
 public class Book { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Description { get; set; } } 

(PSすべてのフィールドは仮想でなければなりません-この要件は、遅延読み込み(遅延読み込み)およびNHibnerateがオブジェクトのすべての変更を追跡するために必要です。)

クラスを作成したら、そのマッピングを作成します。 これを行うには、Models-> NHibernateフォルダーにxml-file“ Book.hbm.xml”を作成します。 ( 注意!。
  1. すべてのマッピングファイルには、* .hbm.xml拡張子が必要です。
  2. このファイルのプロパティに移動し(Book.hbm.xml-> [プロパティ]を右クリック)、[詳細]リストで[ ビルドアクション]プロパティを[ 埋め込みリソース]に変更します 。 他の* .hbm.xmlファイルについても同じことを再度行う必要があります。 指定しない場合は、行configuration.AddAssembly(typeof(Book).Assembly)で指定します。 クラスNhibernateHelper(後で作成されます)は、クラスBookがそのマッピングファイルを見つけることができないというエラーが発生します。


 <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" assembly="NhibernateMVC" namespace="NhibernateMVC.Models"> <class name="Book" dynamic-update="true" > <cache usage="read-write"/> <id name="Id" type="int"> <generator class="native" /> </id> <property name="Name" /> <property name="Description" /> </class> </hibernate-mapping> 

ここで何に注意する必要がありますか。 まず、アセンブリと名前空間はBookクラスと同じでなければなりません。 idが<generator class = "native" />だったのは、guidが好きではなく、データベースの機能(これはSql ServerのID)に応じて、使用するタイプ(identity、sequenceまたはhilo)を決定するためです。


xmlマッピングを作成したら、ルートディレクトリにNHibernateHelper.csクラスを作成します。
  public class NHibernateHelper { public static ISession OpenSession() { var configuration = new Configuration(); var configurePath = HttpContext.Current.Server.MapPath(@"~\Models\Nhibernate\nhibernate.cfg.xml"); configuration.Configure(configurePath); //    Book.hbm.xml Embedded Resource,          configuration.AddAssembly(typeof(Book).Assembly); ISessionFactory sessionFactory = configuration.BuildSessionFactory(); // Nhibernate         . new SchemaUpdate(configuration).Execute(true, true); return sessionFactory.OpenSession(); } } 

ISessionConfigurationのセットアップの詳細については、ISessionFactoryの構成を参照してください。

これらすべての操作の最後に、次のファイルが作成されました。


ここで、NHibernateがデータベースにBookテーブルを作成する方法を見てみましょう。 ControllersフォルダーにHomeControllerクラスを作成し、次のコードを記述します。
  public ActionResult Index() { var session = NHibernateHelper.OpenSession(); return View(); } 

ビューがどのように表示されるか今は興味がありません。空にします。 アプリケーションを起動し、SQL Serverデータベースに移動します(できれば!)NhibernateTutorデータベースにBookテーブルが表示されます。 そこで、必要に応じてデータ型を変更できます(nvarchar(255)do nvarchar(MAX)、but not int!)。 データを入力するまで、最初に接続を設定します(1対1接続が表示されると、MindテーブルがBookテーブルに対応していないというエラーが表示されます)またはデータを入力してから削除します。



次に、テーブル間のリレーションシップの設定に移りましょう。

1.1関係
多対多
Book.csAuthor.cs
 private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 

Book.hbm.xmlAuthor.hbm.xml
 <property ~~~/> ........................................... <set name="Authors" table="Book_Author" cascade="save-update"> <key column="BookId"/> <many-to-many class="Author" column="AuthorId"/> </set> 

 <property ~~~/> ........................................... <set name="Books" table="Book_Author" inverse="true" cascade = "save-update"> <key column="AuthorId"/> <many-to-many class="Book" column="BookId"/> </set> 


これらのクラスのxml-mappingを見てみましょう。 setタグから始めましょう。これは.NET ISetに使用されます。 コレクションのタグの詳細については、 コレクションの値のコレクションをご覧ください。 コレクションの表と、それらに適用されるタグを以下に示します。
.Netコレクションマッピング
IEnumerable / ICollection / IListかばん
順序付きのIListリスト
イセットセット
IDictionary地図




多対一(1対多)
Book.csSeries.cs
 public virtual Series Series { get; set; } 

 private IList<Book> _books; public virtual IList<Book> Books { get { return _books ?? (_books = new List<Book>()); } set { _books = value; } } 

Book.hbm.xml
Series.hbm.xml
 <many-to-one name="Series" class="Series" column="Series_id" cascade = "save-update"/> 

 <bag name="Books" inverse="true"> <key column="Series_id"/> <one-to-many class="Book"/> </bag> 


だから、私は何と言うことができますか? IListがあり、column = "Series_id"がBookテーブルにSeries_Id列を作成するため、タグ "bag"を使用しました。残りは上記で説明しました。

一対一
Book.csMind.cs
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 
 public virtual Book Book { get; set; } 
Book.hbm.xmlMind.hbm.xml
 <one-to-one name="Mind" class="Mind" constrained="true" cascade = "All"/> 
 <one-to-one name="Book" class="Book" /> 


そして、ここはすでに面白いです! constrained =“ true”は、Bookテーブルの各レコードについてMindテーブルにレコードが存在する必要があることを意味します。つまり、BookテーブルのIdはMindテーブルのIdと等しくなければなりません。 Mindテーブルを忘れてBookオブジェクトを保存しようとすると、Nhibernateはデータを保存できないという例外をスローします。 つまり、最初にBookオブジェクトのMindオブジェクトを作成する必要があります。 常にMindオブジェクトを作成するのは非常に面倒なので、保存するときにBookオブジェクトを作成すると、以下のコードでMindオブジェクトが初期化され、Mindテーブルに入力する時間が常にあります。
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

Cascade =“ All”テーブルを保存、変更、削除すると、Bookテーブルも保存、変更され、Mindテーブルが削除されます。 したがって、すべての接続を作成しました。データを保存、編集、または削除して接続を確認します。 以下のネタバレの下の詳細。

マッピングパフォーマンステスト:CRUD操作
次のようにHomeControllerを変更して、データベースにデータを保存、更新、削除するテストアプリケーションを作成しましょう(コードの不要なセクションについてコメントします)。
 public ActionResult Index() { using (ISession session = NHibernateHelper.OpenSession()) { using (ITransaction transaction = session.BeginTransaction()) { //,  var createBook = new Book(); createBook.Name = "Metro2033"; createBook.Description = " "; createBook.Authors.Add(new Author { Name = "" }); createBook.Series = new Series { Name = "" }; createBook.Mind = new Mind { MyMind = " " }; session.SaveOrUpdate(createBook); // ( ) var updateBook = session.Get<Book>(1); updateBook.Name = "Metro2033"; updateBook.Description = " "; updateBook.Authors.ElementAt(0).Name = ""; updateBook.Series.Name = ""; updateBook.Mind.MyMind = "11111"; session.SaveOrUpdate(updateBook); // ( ) var deleteBook = session.Get<Book>(1); session.Delete(deleteBook); transaction.Commit(); } var criteria = session.CreateCriteria<Book>(); criteria.CreateAlias("Series", "series", JoinType.LeftOuterJoin); criteria.CreateAlias("Authors", "author", JoinType.LeftOuterJoin); criteria.CreateAlias("Mind", "mind", JoinType.LeftOuterJoin); criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); var books = criteria.List<Book>(); return View(books); } } 

次のように表現を変更します。
 @model IEnumerable<NhibernateMVC.Models.Book> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <style> th, td { border: 1px solid; } </style> </head> <body> <p>@Html.ActionLink("Create New", "Create")</p> <table> <tr> <th>@Html.DisplayNameFor(model => model.Name)</th> <th>@Html.DisplayNameFor(model => model.Mind)</th> <th>@Html.DisplayNameFor(model => model.Series)</th> <th>@Html.DisplayNameFor(model => model.Authors)</th> <th></th> </tr> @foreach (var item in Model) { <tr> <td>@Html.DisplayFor(modelItem => item.Name)</td> <td>@Html.DisplayFor(modelItem => item.Mind.MyMind)</td> @{string strSeries = item.Series != null ? item.Series.Name : null;} <td>@Html.DisplayFor(modelItem => strSeries)</td> <td> @foreach (var author in item.Authors) { string strAuthor = author != null ? author.Name : null; @Html.DisplayFor(modelItem => strAuthor) <br /> } </td> <td> @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | @Html.ActionLink("Details", "Details", new { id = item.Id }) | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) </td> </tr> } </table> </body> </html> 

Author、Mind、およびSeriesに適切なフィールドを作成することで、自分でできると思います。 すべての操作を順番に確認すると、次のことがわかります。
  • 作成および更新操作中に、Bookテーブルに関連付けられたすべてのデータが更新されます(Cascade = "save-update"またはcascade = "all"を削除すると、関連付けられたデータは保存されません)
  • テーブルBook、Mind、Book_Authorからデータを削除すると、Cascade = "save-update"があるため、残りのデータは削除されません。
  • テーブルBook、Mind、Book_Authorからデータを削除すると、Cascade = "save-update"があるため、残りのデータは削除されません。

さらに、 Criteriaは属性とFluentの両方で機能するため、このコードを使用して他のマッピングオプションのリンクを確認できます。 また、データベース内のキーを確認することを忘れないでください。あなたが犯した間違いは決してわかりません。これについては後で学びます。 たとえば、Bookテーブルは、BookIdキーではなく、Book_AuthorテーブルのAuthorIdをキーで参照します。


詳細情報はこちらをご覧ください。
NHibernateリファレンスドキュメント

2.属性
Nhibernateのアドインです。
長所:
+個別のファイル(* .hbm.xml)を作成し、クラスフィールドのすぐ上に属性を書き込む必要はありません。つまり、エンティティとマッピングが近くにあります。
+ Intellisense 50/50サポート(!)。 属性(名前など)を記述するためのヒントがありますが、文字列として表示されるプロパティについてはありません。
+ xmlファイルから属性に簡単に切り替えられます。
短所:
-コードの可読性が悪化しています。
-コンパイル時の検証の欠如。
-複数の属性で構成されるプロパティの場合、インデックスを登録する必要があります。

インターネット上のNHibernate.Mapping.Attributesには、 nhibernate.infoの Webサイトにも資料がほとんどありませんが、その章は1つだけです! Nhibernate * .hbm.xmlファイルと同じ設定があります。 したがって、 厄介な * .hbm.xmlファイルの代わりに属性を使用します。 したがって、属性を使用していて問題がある場合は、* .hbm.xml-filesに適用可能なソリューションを使用してください。これらの構文は同じであるため、簡単に把握できます。
  1. 属性を使用する前に、最初にすべてのマッピング(* .hbm.xml)ファイルを削除します。これらは不要になります。 ( Nhibernate.cfg.xml leave!)
  2. 属性を操作するには、NHibernate.Mapping.Attribute.dllが必要です。 パッケージマネージャーコンソールからインストールします 。ここでInstall-Package NHibernate.Mapping.Attributesを記述します
  3. NHibernateHelperクラスを次のように変更します

  public class NHibernateHelper { public static ISession OpenSession() { var configuration = new Configuration(); var configurePath = HttpContext.Current.Server.MapPath(@"~\Models\Nhibernate\nhibernate.cfg.xml"); configuration.Configure(configurePath); //configuration.AddAssembly(typeof(Book).Assembly);     \\ HbmSerializer.Default.Validate = true; var stream = HbmSerializer.Default.Serialize(Assembly.GetAssembly(typeof(Book))); configuration.AddInputStream(stream); //*****************************************************************************************************\\ ISessionFactory sessionFactory = configuration.BuildSessionFactory(); // Nhibernate         . new SchemaUpdate(configuration).Execute(true, true); return sessionFactory.OpenSession(); } } 


今こそ属性を書くときです。 次のように属性を追加してBookクラスを変更します
  [Class] public class Book { [Id(0, Name = "Id")] [Generator(1, Class = "native")] public virtual int Id { get; set; } [Property] public virtual string Name { get; set; } [Property] public virtual string Description { get; set; } } 

何に注意する必要がありますか? まず、マップする各プロパティに属性が必要です。 第二に、インデックスID(0 ...)およびジェネレーター(1 ...)に注意しましたか? インデックスは、複数の属性で構成されるプロパティに適用する必要があります。 これは、NHMAが属性からその場で* .hbm.xmlファイルを生成し、xml要素を書き出す順序を知る必要があるためです。 (残念ながら、リフレクションを使用した属性の順序はサポートされていません)。
Bookテーブルをデータベースから削除します(削除することはできません。これは確認のためです)。プロジェクトを実行し、データベースにBookテーブルがなかった場合は作成されます。
構文は* .hbm.xmlファイルの構文と同じであるため、関係については記述しません。唯一の違いは、コレクションの場合、インデックスを登録する必要があることです。

2.1関係(表内)
多対多
Book.csAuthor.cs
 [Set(0, Table = "Book_Author", Cascade = "save-update")] [Key(1, Column = "BookId")] [ManyToMany(2, ClassType = typeof(Author), Column = "AuthorId")] private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 [Set(0, Table = "Book_Author", Inverse = true, Cascade = "save-update")] [Key(1, Column = "AuthorId")] [ManyToMany(2, ClassType = typeof(Book), Column = "BookId")] private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 


多対1、1対多
Book.csSeries.cs
 [ManyToOne(Name = "Series", Column = "SeriesId", ClassType = typeof(Series), Cascade = "save-update")] public virtual Series Series { get; set; } 

 [Bag(0, Name = "Books", Inverse = true)] [Key(1, Column = "SeriesId")] [OneToMany(2, ClassType = typeof(Book))] private IList<Book> _books; public virtual IList<Book> Books{ get { return _books?? (_books= new List<Book>()); } set { _books= value; } } 


一対一
Book.csMind.cs
 [OneToOne(Name = "Mind", ClassType = typeof(Mind), Constrained = true, Cascade = "All")] private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

 [OneToOne(Name = "Book", ClassType = typeof(Book))] public virtual Book Book { get; set; } 



3. ByCodeのマッピング
長所:
+追加のライブラリは必要ありません(属性の場合のように)
+ Intellisense 100のサポート(!)。
+ * .Hbm.xmlファイルとNhibernate.cfg.xmlは必要ありません
+ Fluent-Nhibernate(ラムダ式)を最大限に活用し、* .hbm.xmlファイルの構文を作成しました。
短所:
-カスケードのSave-Updateプロパティを削除しました(Cascade.Persistを使用できますが、それでも可能です)。
-構造(特に、クラス間の関係)は、* .hbm.xmlファイルの要素に正確に対応していません。

更新されます...
  1. nhibernate.cfg.xmlファイルを削除します
  2. NHibernateHelperクラスを次のように変更します

  public class NHibernateHelper { public static ISession OpenSession() { var cfg = new Configuration() .DataBaseIntegration(db => { db.ConnectionString = @"Server=..\SQLENTERPRISE;initial catalog=NhibernateTutor;Integrated Security=SSPI;"; db.Dialect<MsSql2008Dialect>(); }); var mapper = new ModelMapper(); mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes()); HbmMapping mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); cfg.AddMapping(mapping); new SchemaUpdate(cfg).Execute(true, true); ISessionFactory sessionFactory = cfg.BuildSessionFactory(); return sessionFactory.OpenSession(); } } 


トレンドに気づきましたか? 各メソッドは、Nhibernateのファイルの1つを削除します。 xmlファイルには* .hbm.xmlファイルとnhibernate.cfg.xmlファイルがあり、属性は不要になりました* .hbm.xmlファイルは、マッピングbyCodeでnhibernate.cfg.xmlは不要になりました。 新しいメソッドで削除されるのは興味深いことです(そしてまったく削除されますか?)。

Bookクラスとそのマッピングは次のようになります。
  public class Book { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Description { get; set; } } public class BookMap : ClassMapping<Book> { public BookMap() { Id(x => x.Id, map => map.Generator(Generators.Native)); Property(x=>x.Name); Property(x=>x.Description); } 


3.1関係(テーブル内)
多対多
Book.csAuthor.cs
 private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 

BookMap.csAuthorMap.cs
 Set(a => a.Authors, c => { c.Cascade(Cascade.Persist); c.Key(k => k.Column("BookId")); c.Table("Book_Author");}, r=>r.ManyToMany(m=>m.Column("AuthorId"))); 

 Set(a => a.Books, c => { c.Cascade(Cascade.All); c.Key(k => k.Column("AuthorId")); c.Table("Book_Author"); c.Inverse(true); }, r => r.ManyToMany(m => m.Column("BookId"))); 


多対1、1対多
Book.csSeries.cs
 public virtual Series Series { get; set; } 

 private IList<Book> _books; public virtual IList<Book> Books{ get { return _books?? (_books= new List<Book>()); } set { _books= value; } } 

BookMap.csSeriesMap.cs
 ManyToOne(x => x.Series, c => { c.Cascade(Cascade.Persist); c.Column("Series_Id"); }); 

 Bag(x => x.Books, c => { c.Key(k => k.Column("Series_Id")); c.Inverse(true); }, r => r.OneToMany()); 



一対一
Book.csMind.cs
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

 public virtual Book Book { get; set; } 

BookMap.csMindmap.cs
 OneToOne(x=>x.Mind, c=>{c.Cascade(Cascade.All); c.Constrained(true);}); 

 OneToOne(x=>x.Book, c=>c.Cascade(Cascade.None)); 



詳細はこちらStackOverflow Mapping-By-Code

4.フルーエント
NHibernate XMLファイルの標準表示に代わるものを提供します。 XMLファイルを記述する代わりに、厳密に型指定されたC#コードでマッピングを記述します(ラムダ式を使用)。 これにより、リファクタリングが行われ、コードが読みやすくなり、記述しやすくなります。
長所:
+ 100%インテリセンスのサポート!
+ 優れたFluent-Nhibernateのドキュメント
+コンパイル時の検証
+ Nhibernate.cfg.xmlファイルを作成する必要はありません。接続文字列を含むすべての設定をNhibernateHelperで指定できます。
短所:
-他のバージョンのNHibernateと比較して、マッピング構文は少し変わっています。

FluentNhibernateとNhibernateはわずかに異なるため、アプリケーションを再作成しているかのように記述させてください。 それでは、新しいアプリケーションを作成しましょう。
  1. パッケージマネージャーコンソールで、 install-package fluentnhibernateを記述します。
  2. 「Models」フォルダーで、「Book.cs」クラスを作成します(Models-> Book.cs)
  3. NHibernateフォルダーをモデルに追加し、NHibernateHelper.csクラスを作成します(モデル-> NHibernate-> NHibernateHelper.cs)

 public class NHibernateHelper { public static ISession OpenSession() { ISessionFactory sessionFactory = Fluently.Configure() .Database(MsSqlConfiguration.MsSql2008.ConnectionString(@"Server=..\SQLENTERPRISE; initial catalog= Biblioteca; Integrated Security=SSPI;").ShowSql() ) .Mappings(m =>m.FluentMappings.AddFromAssemblyOf<Book>()) .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true)) .BuildSessionFactory(); return sessionFactory.OpenSession(); } } 


このNhibernateHelper.csでは、ここでデータベースに接続文字列を書き込むことに注意してください。 はい、ラムダ式があります。

Book.csクラスを埋める
 public class Book { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual string Description { get; set; } } 

マッピングクラスを作成します
  public class BookMap : ClassMap<Book> { public BookMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.Description); } } 

次に、ControllersフォルダーにHomeControllerクラスを作成し、次のコードを記述します。
 public ActionResult Index() { var session = NHibernateHelper.OpenSession(); return View(); } 

ビューを作成します。SQLServerでアプリケーションを起動すると、Bookテーブルが作成されます。

4.1リレーション(テーブル内)
多対多
Book.csAuthor.cs
 private ISet<Author> _authors; public virtual ISet<Author> Authors { get { return _authors ?? (_authors = new HashSet<Author>()); } set { _author = value; } } 

 private ISet<Book> _books; public virtual ISet<Book> Books{ get { return _books?? (_books= new HashSet<Book>()); } set { _books= value; } } 

BookMap.csAuthorMap.cs
 HasManyToMany(x => x.Authors) .Cascade.SaveUpdate() .Table("Book_Author"); 

 HasManyToMany(x => x.Books) .Cascade.All() .Inverse().Table("Book_Author"); 


多対1、1対多
Book.csSeries.cs
 public virtual Series Series { get; set; } 

 private IList<Book> _books; public virtual IList<Book> Books{ get { return _books?? (_books= new List<Book>()); } set { _books= value; } } 

BookMap.csSeriesMap.cs
 References(x => x.Series).Cascade.SaveUpdate(); 

 HasMany(x => x.Books) .Inverse(); 


Referencesメソッドは多対1側に適用され、HasManyメソッドは他の1対多側に適用されます。

一対一
Book.csMind.cs
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } 

 public virtual Book Book { get; set; } 

BookMap.csMindmap.cs
 HasOne(x => x.Mind).Cascade.All().Constrained(); 

 HasOne(x => x.Book); 


.Constrained()メソッドは、NHibernateにBookテーブルのエントリについて、Mindテーブルのエントリが一致する必要があることを伝えます(MindテーブルのIDはBookテーブルのIDと等しくなければなりません)

クエリオプション(NHibernateクエリ)

NHibernateには、次のような強力なクエリツールがあります。


IDリクエスト
 //   , ( Get  Load) var book = session.Get<Book>(1); 

SQLCreateQueryメソッド
 //SQl- var queryBook = string.Format(@"select Id, Name, Description from Book"); //    var books = session.CreateSQLQuery(queryBook) //SQl-    .SetResultTransformer(Transformers.AliasToBean(typeof(Book))) .List<Book>().ToList(); 

制限付きリスト
 //hql var hqlQuery = session.CreateQuery("from Book b where b.Series.Id = ? order by p.Id") // 0   int=2 .SetInt32(0,2); var books = hqlQuery.List<Book>(); //NHibernate.Linq (session.Linq in NH 2/session.Query in NH3) var linq = (from book in session.Query<Book>() where book.Series.Id == 2 orderby book.Id select book); var books = linq.ToList(); return View(books); //criteria var criteria = session.CreateCriteria<Book>() //"Restrictions"   "Expression" .Add(Restrictions.Eq("Series.Id", 3)) //Order .AddOrder(Order.Asc("Id")); var books = criteria.List<Book>(); //query over var queryOver = session.QueryOver<Book>() .Where(x => x.Series.Id == 2) .OrderBy(x => x.Id).Asc; var books = queryOver.List(); return View(books); 


Join、Projectingなど、NHibernate Queryで同様のクエリを作成したかったのですが、 NHibernate QueriesおよびNHibernate More Queriesからそれに関する優れた記事がすでにあることがわかりました。

QueryOverに興味がある場合、そのクエリのタイプはNH3のQueryOverにあります。

この記事は終わりに近づいているので、次の資料で仕上げたいと思いました。

遅延ロードと熱心なロード(遅延ダウンロードと貪欲なダウンロード)
遅延読み込みとイーガー読み込みは、NHibernateが必要なデータをエンティティのナビゲーションプロパティに読み込むために使用する方法です。
-> 遅延読み込み-遅延読み込み 。 エンティティ(ブック)に初めてアクセスすると、対応する関連データは読み込まれません。 ただし、ナビゲーションプロパティ(Book.Genres)に初めてアクセスすると、関連付けられたデータが自動的に読み込まれます。 同時に、データベースに対して多くのクエリが作成されます。1つはエンティティ用で、もう1つはデータがダウンロードされるたびに実行されます。

 //   (View) @foreach (var item in Model) { //     Book @foreach (var genre in item.Genres) { //   Genres,    Book @Html.DisplayFor(modelItem => genre.Name) <br /> } } 

-> Eagerloading-貪欲なダウンロード 。 エンティティにアクセスすると、データがロードされます。 通常、この後にすべてのデータを返す結合要求が続きます。
 //   (View) @foreach (var item in Model) { //    Book     . @foreach (var genre in item.Genres) { @Html.DisplayFor(modelItem => genre.Name) <br /> } } 


NHibernateは、貪欲なダウンロードにフェッチ戦略を使用します。

例としてQuery Overを使用して、EagerLoadingおよびLazyLoadingのダウンロードを見てみましょう。
---クエリオーバー-ダウンロードコードの遅延読み込み---
  using (ISession session = NHibernateHelper.OpenSession()) { Genre genreAl = null; Author authorAl = null; Series seriesAl = null; var books = session.QueryOver<Book>() //Left Join   Genres .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Series, () => seriesAl, JoinType.LeftOuterJoin) //  id   Book. .TransformUsing(Transformers.DistinctRootEntity).List(); return View(books); } 

---クエリオーバー-EagerLoadingダウンロードコード---
 using (ISession session = NHibernateHelper.OpenSession()) { var books = session.QueryOver<Book>() .Fetch(a => a.Authors).Eager.Fetch(s => s.Series).Eager .TransformUsing(Transformers.DistinctRootEntity).List(); return View(books); 

ご覧のとおり、FetchはすべてのデータをBookオブジェクトにすぐにバインドするため、前の例のようにLeftJoinを使用しませんでした。

Fecthについて-ここで読むことができる戦略Nhibernate Fetch戦略と、レイジーまたはイーガーロードを使用したマッピングについて-here 属性lazy、fetch、batch-sizeNhibernateInfo に関する記事もあります-遅延熱心な読み込みこの

記事は終わりました。ご清聴ありがとうございました。

Source: https://habr.com/ru/post/J265371/


All Articles