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.cs Author.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.xml Author.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.cs Series.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.cs Mind.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.xml Mind.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.cs Author.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.cs Series.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.cs Mind.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.cs Author.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.cs AuthorMap.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.cs Series.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.cs SeriesMap.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.cs Mind.cs
 private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } }
      
      





 public virtual Book Book { get; set; }
      
      





BookMap.cs Mindmap.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.cs Author.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.cs AuthorMap.cs
 HasManyToMany(x => x.Authors) .Cascade.SaveUpdate() .Table("Book_Author");
      
      





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







多対1、1対多

Book.cs Series.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.cs SeriesMap.cs
 References(x => x.Series).Cascade.SaveUpdate();
      
      





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







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



一対一

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





 public virtual Book Book { get; set; }
      
      





BookMap.cs Mindmap.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 に関する記事もあります-遅延熱心な読み込みこの



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



All Articles