著者は、XMLのNHibernateを取り除くというタスクを設定しました(いわばxmlless)。 したがって、私たちのプロジェクトではそうではありません。 絶対に。 代わりに、ラムダ式とメソッドチェーンを使用してデータベースを調整し、エンティティをマップする、流(な( "fluid"または "flexible")インターフェイスが提供されます。
必要条件
必要なもの:
- Oracleサーバー(私の場合は11.2.0.1.0)
- Oracle DAC(私の場合は11.2.0.2.1)、Oracle Client、またはOracleデータベースへのアクセスのその他のプロバイダー。
将来の問題を回避するには、サードパーティのユーティリティなどを使用してデータベースに接続できることを確認してください。 クライアント設定は次の場所にあります。
%Oracle DAC/Client%\product\11.2.0\client_1\Network\Admin\tnsnames.ora
私の場合、ファイルは次のようになります。
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = orasrvxp)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
プロジェクトを作成する
Visual Studio 2010で新しいコンソールプロジェクトを作成し、FluentExampleという名前を付けます。 NuGet Package Managerを使用して、必要なパッケージをすばやく見つけ、受け取り、インストールします。 ライブラリを手動でインストールすることもできます。
プロジェクトファイルを右クリックし、[ライブラリパッケージ参照の追加...]をクリックします。 検索フィールドの[オンライン]タブで、「fluent」と入力します。
Fluent NHibernate自体に加えて、すべての依存関係がロードされます(Castle.Core、Iesi.Collections、NHibernate、NHibernate.Castle)。
私は、図書館のウェブサイトのネイティブな例に基づいて、図書館の機能を簡単かつ十分に説明します。 スキームの形式は次のとおりです。
プロジェクトで、2つのサブフォルダーを作成します:エンティティーとマッピング。ここにエンティティーとそれに応じたマッピングが配置されます。
エンティティの説明
最初のエンティティ、従業員。 従業員には、名前、姓、および職場があります。店です。 エンティティフォルダーで、次のコードを使用して新しいクラスを追加します。
public class Employee
{
public virtual int Id { get ; private set ; }
public virtual string FirstName { get ; set ; }
public virtual string LastName { get ; set ; }
public virtual Store Store { get ; set ; }
}
* This source code was highlighted with Source Code Highlighter .
次の2つの点に注目してください。
- 以降、
Id
プロパティと1Id
リストプロパティは、プライベートセッターで宣言されます。 NHibernateのみが(リフレクションを介して)Id
の値を設定し、コンストラクターでリストを初期化します。 - NHibernateはエンティティのプロキシクラスを作成するため、すべてのプロパティは
virtual
修飾子で宣言されます。プロパティのオーバーロードを有効にする必要があります。
次に並んでいるのは、名前、価格、およびそれらを販売する店舗のリストを持つ製品です。
public class Product
{
public virtual int Id { get ; private set ; }
public virtual string Name { get ; set ; }
public virtual double Price { get ; set ; }
public virtual IList<Store> StoresStockedIn { get ; private set ; }
public Product()
{
StoresStockedIn = new List <Store>();
}
}
* This source code was highlighted with Source Code Highlighter .
リストにはプライベートセッターがあり、上記のようにコンストラクターで初期化が行われます。
名前のある店舗のクラス、および商品と従業員のリスト:
public class Store
{
public virtual int Id { get ; private set ; }
public virtual string Name { get ; set ; }
public virtual IList<Product> Products { get ; private set ; }
public virtual IList<Employee> Staff { get ; private set ; }
public Store()
{
Products = new List <Product>();
Staff = new List <Employee>();
}
public virtual void AddProduct(Product product)
{
product.StoresStockedIn.Add( this );
Products.Add(product);
}
public virtual void AddEmployee(Employee employee)
{
employee.Store = this ;
Staff.Add(employee);
}
}
* This source code was highlighted with Source Code Highlighter .
このクラスでは、NHibernateでは関連エンティティを保存する前に関係の両側を定義する必要があるため、少しロジックを説明します。
ここで、エンティティの説明が終わります。 製品とストア間の多対多の関係を実装するためのリンクテーブルについては、以下で説明します。
Mappimエンティティ
さらに、従来のNHibernateを使用する場合は、xmlマッピングファイルとデータベース構成の作成を開始する必要があります。 しかし、ここでFluent NHibernateが有効になります。
以下で説明するすべてのマッピングクラスは、Mappingsフォルダーにあります。
Employee
クラスを表示することから始めましょう。
using FluentExample.Entities;
using FluentNHibernate.Mapping;
namespace FluentExample.Mappings
{
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
}
}
}
* This source code was highlighted with Source Code Highlighter .
表示コード自体は、FluentNHibernateライブラリの
ClassMap
から継承したクラスのコンストラクターに配置され
ClassMap
。 Fluent NHibernateがマッピングを見つけるためには、
public
修飾子でクラスを宣言する必要があります。 すぐに完全なマッピングを検討してください。
public EmployeeMap()
{
Table( "Employee" );
Id(e => e.Id)
.GeneratedBy.Sequence( "Employee_seq" );
Map(e => e.FirstName);
Map(e => e.LastName);
References(e => e.Store);
}
* This source code was highlighted with Source Code Highlighter .
最初の行の
Table()
、マップするテーブルの名前を担当します。 以下に、名前を明示的に指定する理由を説明します。
Id()
メソッドでは、オブジェクトが識別するフィールドを示します(NHibernate:
<id>
)。 自動インクリメントでデータベースを使用した場合、Fluent NHibernateは自動的にタイプを認識し、IDジェネレーター(NHibernate:
<generator>
)を割り当てます。 ただし、Oracleには自動インクリメントがないため、メソッドチェーンの後半で示されるシーケンスを使用します。
次の2行は、タイプと名前が自動的に決定されるスカラープロパティ(NHibernate:
<property>
)の表示を示しています。 これは、プロパティの命名規則を使用して実装されます。
Column()
メソッドを使用して列名を手動で指定することもできますが、それでもデフォルトの規則を使用するか、独自の規則を設定することをお勧めします。 契約の詳細 。
次の行は、オブジェクトが単数形の
Store
クラスを参照していること、つまり、多対多の関係を実装していることを示しています。 外部キー名は、やはり規則に従って、Store_idと見なされます。 外部キー列は、
Column()
メソッドでオーバーライドできます。
References()
メソッドは、「多くの」側、リレーションシップの反対側(「1つ」)で使用され、
HasMany()
(NHibernate:
<bag>
)メソッドが使用され、キーフィールドの名前を変更するための対応するメソッドは
KeyColumn()
です。
Table()
メソッドに戻りましょう。 ここでのポイントは、デフォルトでは、テーブル名を表示するとき、Fluent NHibernateはそれらを引用符(契約など)で囲みます。つまり、テーブルには引用符とともに「Employee」という名前が付けられます。 Oracleでは、引用符で囲まれた名前のみが大文字と小文字を区別します。 この例では、引用符を使用せず、テーブル名の大文字と小文字を区別せず、引用符を付けないようにするため、明示的に示しました。
ストアのマッピングに移りましょう。
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Table( "Store" );
Id(x => x.Id)
.GeneratedBy.Sequence( "Store_seq" );
Map(x => x.Name);
HasMany(x => x.Staff)
.Inverse()
.Cascade.All();
HasManyToMany(x => x.Products)
.Cascade.All()
.Table( "StoreProduct" );
}
}
* This source code was highlighted with Source Code Highlighter .
ここで、前述の
Employee
クラスの対称的な
HasMany()
呼び出しを確認します。
HasManyToMany()
メソッドも使用されます。これは、
Table()
メソッドによってチェーンで名前が指定された中間テーブルを介して、ストアと製品の間の多対多の関係を実装します。
Inverse()
メソッドは、コレクションの所有者がリレーションシップのもう一方の端、つまり
Employee
クラスであり、最初に保存されることを示しています。
Cascade.All()
は、イベントを関連アイテムに渡します。 つまり、たとえばストアを削除すると、このストアの製品およびすべての従業員との通信もすべて削除されます。 詳細については、NHibernateのドキュメントを参照してください。
最後に、製品を表示します。
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Table( "Product" );
Id(x => x.Id)
.GeneratedBy.Sequence( "Product_seq" );
Map(x => x.Name);
Map(x => x.Price);
HasManyToMany(x => x.StoresStockedIn)
.Cascade.All()
.Inverse()
.Table( "StoreProduct" );
}
}
* This source code was highlighted with Source Code Highlighter .
以前のマッピングの経験から、ここで新しいものを見つけられないことを願っています。 流fluentなマッピングの詳細をご覧ください 。
次に、Oracleへの接続を設定します。
Oracleに接続する
connectionStringを使用して接続します。 プロジェクトに新しいファイルApp.configを追加し、流hなユーザーの接続文字列をnhibernateパスワードで入力します:
Copy Source | Copy HTML
- <? xml バージョン = "1.0" encoding = "utf-8" ? >
- < 設定 >
- < connectionStrings >
- < 名前を 追加 =「Oracle」
- connectionString = "DATA SOURCE = orcl; PASSWORD = nhibernate; PERSIST SECURITY INFO = True;ユーザーID = fluent"
- providerName = "Oracle.DataAccess.Client" />
- </ connectionStrings >
- </ 設定 >
次に、選択したプロバイダーに付属する
Oracle.DataAccess
アセンブリへのリンクを追加する必要があります。
リンクを追加するためのダイアログはおそらく異なるでしょう-私は生産性向上ツールを使用しています 。
追加されたリンクプロパティ
Copy Local = True
設定し
Copy Local = True
。これは、プロジェクトのバイナリ出力ファイルを含むフォルダーにこのライブラリをコピーする必要があることを示します。
便宜上、小さなヘルパーを使用してFluent NHibernateでセッションを開きます。
using FluentExample.Entities;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Driver;
namespace FluentExample
{
public static class FluentNHibernateHelper
{
private static ISessionFactory _sessionFactory;
public static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null )
{
var dbConfig = OracleDataClientConfiguration.Oracle10
.ConnectionString(c => c.FromConnectionStringWithKey( "Oracle" ))
.Driver<OracleDataClientDriver>()
.ShowSql();
_sessionFactory = Fluently.Configure()
.Database(dbConfig)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Employee>())
.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
}
* This source code was highlighted with Source Code Highlighter .
データベース構成では、
OracleDataClientConfiguration
名前空間の定義済みクラス
OracleDataClientConfiguration
を使用し、作成した接続文字列とNHibernateドライバーを使用するように構成します。 生成されたSQLクエリを表示するオプションを有効にすることもできます。 データベース構成の詳細 。
次に、NHibernate自体の構成を実行します。 データベース構成を置き換え、マッピングのソースを示し、セッションファクトリを要求します。 Fluent Configurationの詳細をご覧ください 。
この段階で、セッションの取得は成功するはずです。
class Program
{
static void Main()
{
using (FluentNHibernateHelper.OpenSession())
{
}
}
}
* This source code was highlighted with Source Code Highlighter .
ベースのテスト
これで、プロジェクトは次のような構造になります。
実際のテストを実行します。
private static void Main()
{
using ( var session = FluentNHibernateHelper.OpenSession())
{
using ( var transaction = session.BeginTransaction())
{
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" };
// . ,
// many-to-many.
AddProductsToStore(barginBasin, potatoes, fish, milk, bread, cheese);
AddProductsToStore(superMart, bread, cheese, waffles);
//
AddEmployeesToStore(barginBasin, daisy, jack, sue);
AddEmployeesToStore(superMart, bill, joan);
//
session.SaveOrUpdate(barginBasin);
session.SaveOrUpdate(superMart);
transaction.Commit();
}
//
using (session.BeginTransaction())
{
var stores = session.CreateCriteria( typeof (Store)). List <Store>();
foreach ( var store in stores)
WriteStorePretty(store);
}
Console .ReadKey();
}
}
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);
}
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();
}
* This source code was highlighted with Source Code Highlighter .
以上です。
Oracleで回路を生成するスクリプトも提供します。
次は?
未実現の機能
著者は、ネイティブライブラリの機能の大部分をサポートしていますが、NHibernateの一部の機能、たとえば
<sql-insert>
はまだ利用できません。
自動マッピング
Fluent NHibernateを使用すると、入力された規則に従うか、独自の規則を定義するだけで、自動的にマッピングを行うことができます。
マッピングテスト
このライブラリを使用すると、作成したマッピングをすばやく同じスタイルでテストできます。