パート2.クラスの作成、データベースへのマッピングおよび入力

クラスとマッピング



ASP.NET MVCおよびSQL Serverを使用したFluentNHibernateのチュートリアル。 パート1

パート3.テーブルからのデータの表示(操作リスト)



前のパートでは、接続のタイプ(1対1、1対多、多対多)、および1つのクラスBookとそのマッピングクラスBookMapを調べました。 第2部では、サブタイトル1.3.1リンクの上にあるデータベース図の前の章で示したように、Bookクラスを更新し、残りのクラスとそれらの間のリンクを作成します。





クラスとマッピングコード(コメント付き)
クラスブック



public class Book { //  public virtual int Id { get; set; } // public virtual string Name { get; set; } // public virtual string Description { get; set; } //   public virtual int MfRaiting { get; set; } //  public virtual int PageNumber { get; set; } //   public virtual string Image { get; set; } //   (  !) public virtual DateTime IncomeDate { get; set; } // (--) // ISet   IList?    (IList)     JOIN ,        JOIN,       ISet public virtual ISet<Genre> Genres { get; set; } // (--) public virtual Series Series { get; set; } //   (--) private Mind _mind; public virtual Mind Mind { get { return _mind ?? (_mind = new Mind()); } set { _mind = value; } } // (--) public virtual ISet<Author> Authors { get; set; } // ,   null  . public Book() { //  (       --  ,     ,   ) Genres = new HashSet<Genre>(); Authors = new HashSet<Author>(); } } //  Book public class BookMap : ClassMap<Book> { public BookMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.Description); Map(x => x.MfRaiting); Map(x => x.PageNumber); Map(x => x.Image); Map(x => x.IncomeDate); // -- HasManyToMany(x => x.Genres) //  All -   ,   ,   ////    .Cascade.SaveUpdate() //         Genre! .Table("Book_Genre"); HasManyToMany(x => x.Authors) .Cascade.SaveUpdate() .Table("Book_Author"); //    References(x => x.Series); // --.  . HasOne(x => x.Mind).Cascade.All().Constrained(); } }
      
      







クラス著者



  public class Author { public virtual int Id { get; set; } //- public virtual string Name { get; set; } // public virtual string Biography { get; set; } // public virtual ISet<Book> Books { get; set; } //  public Author() { Books=new HashSet<Book>(); } } //  public class AuthorMap : ClassMap<Author> { public AuthorMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.Biography); // -- HasManyToMany(x => x.Books) //  All -   ,   ,   //    .Cascade.All() //  .    (Book)     . .Inverse() //         Book! .Table("Book_Author"); } }
      
      







クラスのジャンル



  public class Genre { public virtual int Id { get; set; } //  public virtual string Name { get; set; } //   public virtual string EngName { get; set; } // public virtual ISet<Book> Books { get; set; } //  public Genre() { Books=new HashSet<Book>(); } } //  public class GenreMap : ClassMap<Genre> { public GenreMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.EngName); // -- HasManyToMany(x => x.Books) //  All -   ,   ,   //    .Cascade.All() //  .    (Book)     . .Inverse() //         Book! .Table("Book_Genre"); } }
      
      







クラスの意見:



  public class Mind { public virtual int Id { get; set; } //  public virtual string MyMind { get; set; } //  public virtual string MindFantLab { get; set; } // public virtual Book Book { get; set; } } // ind public class MindMap:ClassMap<Mind> { public MindMap() { Id(x => x.Id); Map(x => x.MyMind); Map(x => x.MindFantLab); //    HasOne(x => x.Book); } }
      
      







クラスサイクル(シリーズ):



  public class Series { public virtual int Id { get; set; } public virtual string Name { get; set; } //  IList,   ISet,    Book, Series      ,     ISet public virtual IList<Book> Books { get; set; } // . public Series() { Books = new List<Book>(); } } public class SeriesMap : ClassMap<Series> { public SeriesMap() { Id(x => x.Id); Map(x => x.Name); // -- HasMany(x => x.Books) ////  .    (Book)     . .Inverse() } }
      
      









少し説明

パブリック仮想ISet <Genre>ジャンル{get; セット; }

パブリック仮想ISet <Author> Authors {get; セット; }



たとえば、多くのIList <Class>に馴染みのないISet <Class>がなぜですか ISetの代わりにIListを使用してプロジェクトを開始しようとしても、大きな違いはありません(テーブルとクラスが作成されます)。 ただし、LeftJoinsのBookクラスにアクセスすると、同時にジャンルと著者のテーブルが表示され、ビュー内のBookテーブル(Distinct Book.Id)から繰り返しないエントリを表示しようとすると、Nhibernateは例外とエラーをスローします。

複数のバッグを同時に取得することはできません。

そのような場合、特にセットはこれを対象としているため、ISetを使用します(重複エントリは無視されます)。



多対多の関係。



作者
HasManyToMany(x => x.Genres)

.Cascade.SaveUpdate()

.Table( "Book_Author");

HasManyToMany(x => x.Books)

.Cascade.All()

.Inverse()

.Table( "Book_Author");



NHibernateには「メイン」テーブルの概念があります。 「Book」テーブルと「Author」テーブルの多対多の関係は同じですが(著者は多くの本を持ち、本は多くの著者を持つことができます)、Nhibernateはプログラマーに2番目に保存されるテーブルを指定することを要求します(メソッドがあります)。つまり、最初にエントリがBookテーブルで作成、更新、削除され、その後Authorテーブルでのみ作成されます。

Cascade.Allは、保存、更新、削除でカスケード操作を実行することを意味します。 つまり、オブジェクトが保存、更新、または削除されると、すべての依存オブジェクトがチェックされ、作成/更新/追加されます(Ps。Cascade.All-> .Cascade.SaveUpdate()を登録できます。代わりにCascade.Delete())

メソッド.Table( "Book_Author"); データベースに「中間」テーブル「Book_Author」を作成します。



多対1、1対多の関係。

シリーズ
参照(x => x.Series).Cascade.SaveUpdate();

HasMany(x => x.Books)

.Inverse();



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



1対1の関係

HasOne(x => x.Mind).Cascade.All()。Constrained();

HasOne(x => x.Book);



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



ここでプロジェクトを開始してBibiliotecaデータベースを見ると、すでに形成された関係を持つ新しいテーブルが表示されます。



次に、作成したテーブルにデータを入力します...

これを行うには、データベースにデータを保存するテストアプリケーションを作成し、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.Genres.Add(new Genre { Name = " " }); createBook.Series = new Series { Name = "" }; createBook.Mind = new Mind { MyMind = " " }; session.SaveOrUpdate(createBook); // ( ) //var series = session.Get<Series>(1); //var updateBook = session.Get<Book>(1); //updateBook.Name = "Metro2034"; //updateBook.Description = ""; //updateBook.Authors.ElementAt(0).Name = ""; //updateBook.Genres.ElementAt(0).Name = ""; //updateBook.Series = series; //updateBook.Mind.MyMind = "11111"; //session.SaveOrUpdate(updateBook); // ( ) //var deleteBook = session.Get<Book>(1); //session.Delete(deleteBook); transaction.Commit(); } Genre genreAl = null; Author authorAl = null; Series seriesAl = null; Mind mindAl = null; var books = session.QueryOver<Book>() //Left Join   Genres .JoinAlias(p => p.Genres, () => genreAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Series, () => seriesAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Mind, () => mindAl, JoinType.LeftOuterJoin) //  id   Book. .TransformUsing(Transformers.DistinctRootEntity).List(); return View(books); } }
      
      







少し説明

  1. var books = session.QueryOver <Book>() -SQLスクリプトの実行のように: Select * From Book ;
  2. .JoinAlias(p => p.Genres、()=> genreAl、JoinType.LeftOuterJoin)-SQLスクリプトの実行と同様:

    SELECT * FROM Book

    inner JOIN Book_Genre ON book.id = Book_Genre.Book_id

    LEFT JOINジャンルON Book_Genre.Genre_id =ジャンル.id
  3. .TransformUsing(Transformers.DistinctRootEntity)-SQLスクリプトの実行のように: SELECT distinct Book.Id ... 、(同じidの重複エントリを削除します)




関連付けの種類

.JoinAlias(p => p.Genres、()=> genreAl、JoinType.LeftOuterJoin)

  1. LeftOuterJoin-左側のテーブル( Book )からすべてのレコードを選択し、右側のテーブル( ジャンル )のレコードをそれらに添付します。 右側のテーブルに対応するレコードが見つからない場合は、Nullとして表示します
  2. RightOuterJoinはLEFT JOINとは異なり、右のテーブル( ジャンル )からすべてのエントリを選択し、左のテーブル( ブック )のエントリをそれらに添付します。
  3. InnerJoin-右側のテーブル( ジャンル )からの対応するレコードを持つ左側のテーブル( ブック )のレコードのみを選択し、右側のテーブルからのレコードをアタッチします




次のように表現を変更します。

インデックスビュー
 @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>@Html.DisplayNameFor(model => model.Genres)</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> @foreach (var genre in item.Genres) { string strGenre = genre!= null ? genre.Name : null; @Html.DisplayFor(modelItem => strGenre) <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>
      
      







すべての操作を順番に確認すると、次のことがわかります。





継承を持つクラスのマッピング。

そして、継承を持つクラスをどのようにマップしますか? 例があるとします:

  //   public class TwoDShape { // public virtual int Width { get; set; } // public virtual int Height { get; set; } } //  public class Triangle : TwoDShape { //  public virtual int Id { get; set; } //  public virtual string Style { get; set; } }
      
      







原則として、このマッピングには複雑なものはありません;派生クラス、つまりTriangleテーブルに対して1つのマッピングを作成するだけです。

  //  public class TriangleMap : ClassMap<Triangle> { public TriangleMap() { Id(x => x.Id); Map(x => x.Style); Map(x => x.Height); Map(x => x.Width); } }
      
      





アプリケーションを起動すると、Bibliotecaデータベースに次の(空の)テーブルが表示されます








All Articles