3. サンプルアプリケーション

ひとまず、本家サイトのソースを載せます。

using System;
using System.IO;
using Examples.FirstProject.Entities;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace Examples.FirstProject
{
  class Program
  {
    private const string DbFile = "firstProgram.db";

    static void Main()
    {
      var sessionFactory = CreateSessionFactory();
     
      using (var session = sessionFactory.OpenSession())
      {
        using (var transaction = session.BeginTransaction())
        {
          // create a couple of Stores each with some Products and Employees
          var barginBasin = new Store { Name = "Bargin Basin" };
          var superMart = new Store { Name = "SuperMart" };
     
          var potatoes = new Product { Name = "Potatoes", Price = 3.60 };
          var fish = new Product { Name = "Fish", Price = 4.49 };
          var milk = new Product { Name = "Milk", Price = 0.79 };
          var bread = new Product { Name = "Bread", Price = 1.29 };
          var cheese = new Product { Name = "Cheese", Price = 2.10 };
          var waffles = new Product { Name = "Waffles", Price = 2.41 };
     
          var daisy = new Employee { FirstName = "Daisy", LastName = "Harrison" };
          var jack = new Employee { FirstName = "Jack", LastName = "Torrance" };
          var sue = new Employee { FirstName = "Sue", LastName = "Walkters" };
          var bill = new Employee { FirstName = "Bill", LastName = "Taft" };
          var joan = new Employee { FirstName = "Joan", LastName = "Pope" };
     
          // add products to the stores, there's some crossover in the products in each
          // store, because the store-product relationship is many-to-many
          AddProductsToStore(barginBasin, potatoes, fish, milk, bread, cheese);
          AddProductsToStore(superMart, bread, cheese, waffles);
     
          // add employees to the stores, this relationship is a one-to-many, so one
          // employee can only work at one store at a time
          AddEmployeesToStore(barginBasin, daisy, jack, sue);
          AddEmployeesToStore(superMart, bill, joan);
     
          // save both stores, this saves everything else via cascading
          session.SaveOrUpdate(barginBasin);
          session.SaveOrUpdate(superMart);
     
          transaction.Commit();
        }
     
        // retreive all stores and display them
        using (session.BeginTransaction())
        {
          var stores = session.CreateCriteria(typeof(Store))
            .List();
     
          foreach (var store in stores)
          {
            WriteStorePretty(store);
          }
        }
     
        Console.ReadKey();
      }
    }

    private static ISessionFactory CreateSessionFactory()
    {
        return Fluently.Configure()
            .Database(SQLiteConfiguration.Standard
                .UsingFile(DbFile))
            .Mappings(m =>
                m.FluentMappings.AddFromAssemblyOf<Program>())
            .ExposeConfiguration(BuildSchema)
            .BuildSessionFactory();
    }

    private static void BuildSchema(Configuration config)
    {
        // delete the existing db on each run
        if (File.Exists(DbFile))
            File.Delete(DbFile);

        // this NHibernate tool takes a configuration (with mapping info in)
        // and exports a database schema from it
        new SchemaExport(config)
            .Create(false, true);
    }

    private static void WriteStorePretty(Store store)
    {
        Console.WriteLine(store.Name);
        Console.WriteLine("  Products:");
                    
        foreach (var product in store.Products)
        {
            Console.WriteLine("    " + product.Name);
        }

        Console.WriteLine("  Staff:");

        foreach (var employee in store.Staff)
        {
            Console.WriteLine("    " + employee.FirstName + " " + employee.LastName);
        }

        Console.WriteLine();
    }

    public static void AddProductsToStore(Store store, params Product[] products)
    {
      foreach (var product in products)
      {
        store.AddProduct(product);
      }
    }
 
    public static void AddEmployeesToStore(Store store, params Employee[] employees)
    {
      foreach (var employee in employees)
      {
        store.AddEmployee(employee);
      }
    }
  }
}

(Program.cs)

Main関数内では、

  • 2つのStore
  • 6つのProduct
  • 5人のEmployee

を生成し、それぞれをStoreに追加し保存、次に保存先から読みだして表示する。という構成になっています。

ここでは、サンプルのままなのでSQLiteでの設定になっていますが、後程PostgreSQL用に変更します。

Configuration

NHibernate用のセッション管理用の実装をします。ここに、データベースへの接続情報等が入力されます。

 

ここでは、サンプルのCreateSessionFactoryをSQLite仕様からPostgreSQL仕様に変更します。

 

前提として

  • localhostのPostgreSQL 9.1.1
  • ポートはデフォルトの5432
  • データベースはtestdb(スキーマはなくても、既に存在する)
  • ユーザ名は「postgres」
  • パスワードは「postgres」

とすると、以下のように変更します。

private static ISessionFactory CreateSessionFactory()
{
  return Fluently.Configure()
   .Database(PostgreSQLConfiguration.PostgreSQL82
   .ConnectionString(x => x
       .Host("localhost")
       .Port(5432)
       .Database("testdb")
       .Username("postgres")
       .Password("postgres")))
   .Mappings(m => m
       .FluentMappings.AddFromAssemblyOf<Program>())
   .ExposeConfiguration(BuildSchema)
   .BuildSessionFactory();
}

利用したPostgreSQLは9.1.1でしたが、8.2用で動くみたいです。(というより、8.1か8.2しか選べない)

 

今回はMappings()内で

AddFromAssemblyOf<Program>()

を呼びましたが、マッピングクラスを個別に呼ぶ場合は

using Examples.FirstProject.Mappings; // 追加

.Mappings(m => m
       .FluentMappings.AddFromAssemblyOf<ProductMap>()
                      .AddFromAssemblyOf<EmployeeMap>()
                      .AddFromAssemblyOf<StoreMap>() )

と、記述してください。

 

あとは、データベーススキーマ(テーブル)を作成するBuildSchemaの中のFile.Delete()のif文をコメントアウトすれば、実行可能です。

private static void BuildSchema(Configuration config)
{
  // delete the existing db on each run
  //if (File.Exists(DbFile))
  //    File.Delete(DbFile);

  // this NHibernate tool takes a configuration (with mapping info in)
  // and exports a database schema from it
    new SchemaExport(config)
      .Create(false, true);
}

実行前に、テーブルは無くてもいいのでtestdbは用意しておいてください。

 

また、ExposeConfiguration(BuildSchema)を呼ぶと毎回リセットされるので注意してください。(リセットしたくない場合はこの行をコメントアウトしてください)

 

実行前

実行結果

実行後