Nhibernate。 DAO +ジェネリック

みなさんこんにちは。 GenericDaoとは何ですか、知っておく必要がありますが、わからない場合:

DAO(略称:英語。データアクセスオブジェクト)-データにアクセスするためのオブジェクト。

ジェネリックとは、C#で使用可能なクラステンプレート(ジェネリック)を使用して、すべてのNHibernateクラスで機能するインターフェイスを作成することを意味します。



1. GenericDaoインターフェイスの作成



それでは始めましょう。 前の記事で、NHibernateを構成する方法について説明しました。 アプリケーション設定ファイルなどはどうあるべきか

まず、データベースにアクセスするためにNHibernate(以降、hibernate、hibernateと呼びます)がどのように動作するかを見てみましょう。

オブジェクトを操作するようにNHibernateを構成できるクラスを分析しましょう。このクラスを見るだけで、どこでも使用しません:

public class DataController

{



private ISessionFactory _sessions;



public DataController()

{

Configuration cfg = new Configuration();

cfg.AddClass( typeof (DataElement)); //

cfg.AddClass( typeof (Pins));

cfg.AddClass( typeof (Properties));

cfg.AddClass( typeof (Library));

_sessions = cfg.BuildSessionFactory(); //



}

}




* This source code was highlighted with Source Code Highlighter .






コンストラクターでは、Configurationクラスのオブジェクトが作成されていることがわかります。これを特定の方法で構成する必要があります。 どのようなハイバークラスがあるかを示します。 その後、セッションのファクトリを構築します。 その後、セッションファクトリを使用して、指定したクラスと正確に連携するセッションを開くことができます。 次に、データベースにデータを保存する方法を見てみましょう。

public DataElement SaveElement(DataElement el)

{

ISession session = _sessions.OpenSession(); //

try

{

session.Save(el); //

return el; // , PK, PK



}

catch (HibernateException e)

{

throw e;

}

finally

{

session.Close(); //

}

}




* This source code was highlighted with Source Code Highlighter .






そのため、ここではDataElementクラスのオブジェクトを操作できます。 しかし、すべてのクラスに対してこのようなメソッドを記述する必要があることがわかります...特に多くのクラスがある場合、誰もがこれを記述することを望んでいません。 メソッドInsert、Update、Deleteを忘れないでください。 合計で4つのhiberクラスがあり、それぞれに少なくとも4つのメソッド、合計16のメソッドがあります。 怠azine ...

これが、DAO +ジェネリックが救いをもたらす場所です。

したがって、すべてのhiberオブジェクトに共通のインターフェイスを作成してみましょう。* type *という単語を使用して、hiberクラスであるタイプをマークします。 使用するhiberクラスのいずれでもかまいません。 私のデータベースでは、すべてのPKテーブルにintフィールドがあります。

public interface IGenericDao

{

*type* Get( int id);

*type* Save(*type*obj);

*type* SaveOrUpdate(*type* obj);

void Delete(*type* obj);

}




* This source code was highlighted with Source Code Highlighter .






すべてのクラスに4つのメソッド(最低)が必要であることがわかります...しかし、どのように型を正しく渡すのでしょうか? など:

public interface IGenericDao<T, ID>

{

T Get(ID id);

T Save(T obj);

T SaveOrUpdate(T obj);

void Delete(T obj);

}




* This source code was highlighted with Source Code Highlighter .






ここで、クラスのテンプレート(ジェネリック型)の使用を開始します。 でも2。 最初の(T)はhiberクラスのテンプレートであり、2番目の(ID)はPKであるタイプのテンプレートです。 つまり データベースからフィールドを取得できます。int型のPKだけでなく、文字列も使用できます。

そこで、GenericDaoインターフェイスを作成しました。次に、このインターフェイスを実装するクラスを作成する必要があります。 しかし、最初に、セッションを思い出しましょう。

2.セッションのファクトリを作成する



データベースからデータを取得、保存、更新、削除するには、セッションを開く必要があることを覚えています。 また、データを取得してhiberクラスのオブジェクトに渡し、セッションを閉じた場合、Lazyを無効にすると(デフォルトでは無効になっている)、オブジェクトのデータは利用できなくなります。 それは何のためですか? プロキシクラスはセッションを通じて必要なデータを参照するため、プロキシクラスとは、ヒーバーのドキュメントをお読みください。 セッションを閉じた後、プロキシクラスがアクセスできないリンクを参照していることがわかりました。 つまり セッションを維持する必要があることがわかりました。 これを行う方法は? セッションは、ISessionインターフェイスを介して記述されます。 そして、私たちは工場セッションからセッションを取ります。 これをどうやってやるの? そして、ここに方法があります:

public class SessionFactory

{

public static void Init() //

{

Configuration cfg = new Configuration();

cfg.AddAssembly(”Win.Objects”); // NHibernate. , .

sessionFactory = cfg.BuildSessionFactory();

}

private static ISessionFactory sessionFactory; // ,

private static ISession threadSession //

{

get

{

return (ISession)CallContext.GetData(”THREAD_SESSION”); // ,

}

set

{

CallContext.SetData(”THREAD_SESSION”, value );

}

}



public static ISession GetSession() // .

{

ISession session = threadSession; //



if (session == null ) // “”

{

session = sessionFactory.OpenSession(); //

threadSession = session; //

}



return session; //

}

}




* This source code was highlighted with Source Code Highlighter .






セッションは必要なときにコンテキストに保存され、GetSession()メソッドを呼び出して、セッションが「生きている」かどうかをチェックし、そうでない場合は新しいセッションを作成し、そうであれば「ライブ」を返します。 初期化に関しては、プログラムの任意の場所で、ただしセッションの使用を開始する前に一度呼び出す必要があります。 メインフォームのコンストラクターで発声します。 以上です。 理解しました...では、IGenericDaoインターフェイスの実装を見てみましょう。

3. IGenericDaoの実装



DAOを実装するためのインターフェイスがあり、セッションを操作するためのクラスがあります。CRUDメソッド(Create、Read、Update、Delete)を記述してジェネリックを操作するだけです。 これが起こります:

public class GenericImpl<T, ID> : IGenericDao<T, ID> // IGenericDao

{

private ISession session //

{

get

{

return SessionFactory.GetSession(); // .

}

}



private Type _type = typeof (T); // , .



public T Get(ID id) //

{

try

{

T result = (T) session.Load(_type, id); // T Load

return result; //

}

catch (HibernateException e)

{

throw e;

}

}



public T Save(T obj)

{

try

{

session.Save(obj);

return obj;

}

catch (HibernateException e)

{

throw e;

}

}



public T SaveOrUpdate(T obj)

{

session.SaveOrUpdate(obj);

return obj;

}



public void Delete(T obj)

{

session.Delete(obj);

}

}




* This source code was highlighted with Source Code Highlighter .






繰り返しになりますが、すべてがとてつもなくシンプルです...これで、任意のhiberクラス用にGenericDaoを作成できます。 これで、GenericImplクラスを使用して任意のオブジェクトを操作できます。

GenericImpl<Library, int > libdao = new GenericImpl<Library, int >(); // Library

Library lib = new Library(); //

lib.Name = “ ”; //

libdao.Save(lib); //

libdao.Get(1); //

libdao.Delete(lib); //

libdao.SaveOrUpdate(lib);//




* This source code was highlighted with Source Code Highlighter .






まあ、美しいですね。 しかし、私たちはそこで止まりません。 私には、DAOの作成方法が気に入らないかもしれません。 私たちの生活を楽にしてみましょう。 どうやって? hiberクラスごとにDAOファクトリを作成します。

4.工場DAO



私たちは何をしますか? クラスごとに一意のDAOを作成しますが、CRUDメソッドはこれ以上作成しません。 どうやってやるの? シンプル。 しかし、順番に...

各hiberクラスのDAOインターフェイスを作成し、ベースIGenericDaoから単純に継承しますが、どのhiberクラスを使用するかを示します。

public interface IDataElementDao : IGenericDao<DataElement, int >{}

public interface ILibraryDao : IGenericDao<Library, int > { }

public interface IPinsDao : IGenericDao<Pins, int > { }

public interface IPropertiesDao : IGenericDao<Properties, int > { }




* This source code was highlighted with Source Code Highlighter .






もちろんマイナスは、クラスごとにインターフェイスを宣言する必要があるが、CRUDメソッドを記述する必要がないことです。 次に、DAOファクトリのインターフェイスを作成します。これにより、各hiberクラスの既製のDaoインターフェイスが提供されます。

public interface IDaoFactory

{

IDataElementDao GetDataElementDao();

ILibraryDao GetLibraryDao();

IPinsDao GetPinsDao();

IPropertiesDao GetPropertiesDao();

}




* This source code was highlighted with Source Code Highlighter .






私はすべてがそれが何であるか明確だと思います。 そして、すべてが非常に美しくなるように、個々のhiberクラスごとにIGenericDAOを実装するクラスを作成します。

public class HDataElement : GenericImpl<DataElement, int >, IDataElementDao{}

public class HLibrary : GenericImpl<Library, int >, ILibraryDao{}

public class HPins : GenericImpl<Pins, int >, IPinsDao{}

public class HProperties : GenericImpl<Properties, int >, IPropertiesDao{}




* This source code was highlighted with Source Code Highlighter .






各hiberクラスにDAOインターフェイスを実装する必要があり、hiberクラスを示すベースGenericImplを継承することで実装することがわかりました。 そして、DAOファクトリを実装します。

public class FactoryDao : IDaoFactory

{

public IDataElementDao GetDataElementDao()

{

return new HDataElement();

}



public ILibraryDao GetLibraryDao()

{

return new HLibrary();

}



public IPinsDao GetPinsDao()

{

return new HPins();

}



public IPropertiesDao GetPropertiesDao()

{

return new HProperties();

}

}




* This source code was highlighted with Source Code Highlighter .






これは、ハイバークラスを操作するための既製のDAOオブジェクトを取得する方法です。 使い方は? このように:

IDaoFactory fact = new FactoryDao(); //



ILibraryDao libdao = fact.GetLibraryDao(); // Library

Library lib = new Library();

lib.Name = “ ”;

libdao.Save(lib);

libdao.Get(1);

libdao.Delete(lib);

libdao.SaveOrUpdate(lib);



IDataElementDao eldao = fact.GetDataElementDao();// DataElement .




* This source code was highlighted with Source Code Highlighter .






結論



未解決の問題がある場合は、それらを声に出してください。それから、あなたの質問が次の記事のトピックに該当することを付け加えます。

これで十分でない人のために、ここに行きます。 Spring FrameWorkとそのSpringAOPを使用して、問題をさらに緩和する方法を次に示します。 これは非常に便利ですが、非常に気まぐれです。

まあ、それだけです。 みんなが理解してくれることを願っています。 いつものように、クレームは受け入れられ、聞かれます。 役に立つといいのですが。)



PS:Habrに関する私の最初のトピック。 この記事が楽しいものになることを願っています。 みなさん、こんにちは!:-)



All Articles