web-dev-qa-db-ja.com

DAOレイヤーを永続レイヤー(JDOやHibernateなど)の上に配置する理由

データアクセスオブジェクト(DAO)は一般的なデザインパターンであり、Sunが推奨しています。しかし、Java DAOの初期の例はリレーショナルデータベースと直接相互作用しました-本質的に、オブジェクトリレーショナルマッピング(ORM)を実行していました。今日、私は次のような成熟したORMフレームワークの上にDAOを見つけます。 JDOとHibernate、そしてそれは本当に良い考えかと思います。

JDOを永続層として使用するWebサービスを開発しており、DAOを導入するかどうかを検討しています。他のオブジェクトのマップを含む特定のクラスを処理するときに問題が発生することが予想されます。

public class Book {
    // Book description in various languages, indexed by ISO language codes
    private Map<String,BookDescription> descriptions;
}

JDOは、これを「BOOKS」テーブルと「BOOKDESCRIPTIONS」テーブルの間の外部キー制約にマップするのに十分賢いです。 BookDescriptionオブジェクトを透過的にロードし(遅延読み込みを使用して)、Bookオブジェクトが永続化されるときにそれらを永続化します。

「データアクセス層」を導入してBookDaoのようなクラスを記述し、その中にすべてのJDOコードをカプセル化するとしたら、このJDOによる子オブジェクトの透過的な読み込みがデータアクセス層を回避しているのではないでしょうか。一貫性を保つために、すべてのBookDescriptionオブジェクトを何らかのBookDescriptionDaoオブジェクト(またはBookDao.loadDescriptionメソッド)を介してロードおよび永続化するべきではありませんか?しかし、そのようにリファクタリングすると、モデルの操作が不必要に複雑になります。

だから私の質問は、ビジネス層で直接JDO(またはHibernate、またはあなたが好きなORM)を呼び出すことの何が問題になっているのかということです。その構文はすでに非常に簡潔であり、データストアに依存しません。データアクセスオブジェクトにカプセル化することの利点は何ですか?

32
Todd Owen

それはあなたのレイヤーの目標が何であるかによります。抽象化を入れて、別のセットに異なるセマンティクスのセットを提供します。一般に、将来のメンテナンスの開発などを簡素化するために、さらに別のレイヤーがあります。しかし、他の用途も考えられます。

たとえば、ORMコード上のDAO(または永続処理)レイヤーは、ビジネスロジックを汚染したくない特殊なリカバリおよびエラー処理機能を提供します。

10
Preet Sangha

あなたはいくつかの点を指摘します。しかし、それでも私はDaoレイヤーを使用しています。理由は次のとおりです。

  1. データベースアクセスはリモートシステムへの呼び出しです。このようなすべての場合(Webサービス、ajaxなど)、対話の粒度は十分に大きい必要があります。多くの小さな呼び出しはパフォーマンスを低下させます。このパフォーマンスの必要性は、多くの場合、システムまたはレイヤー(ここではDaoレイヤー)の異なるビューを必要とします。

  2. 場合によっては、永続化操作はオブジェクトのロード/保存/削除のみです。 1つのユニークなDao(またはスーパークラス; Genericsを検討してください)がこれを担当できるため、これらのメソッドを何度もコーディングする必要はありません。
    しかし、多くの場合、ORMによって自動的に作成されない特定のリクエストを実行するなどの特定のニーズもあります。そこで、特定のDaoメソッドを使用して特定のニーズをコーディングします(再利用は多くの場合可能です)。
    同じレイヤーに定期的かつ特定のニーズがあると、再利用が可能になります(たとえば、インターセプトにより、必要なときにデータベース接続を確実に開いたりコミットしたりできます)。

12
KLE

DAOは時間とともにその意味を失っています。

それが人気のあるパターンになったJ2EEの時代、DAOは、複数のデータソース(あるベンダーのデータベース、別のベンダーのデータベース、ファイル)に同時に対応し、クエリをラップする単一の場所を提供できるクラスでした。データのために通信します。

再利用の余地は十分にあったため、特定のエンティティのDAOオブジェクトは、それ自体がDAOインターフェイスを実装した再利用可能なものを格納する抽象DAOを拡張する可能性があります。

J2EE/EJB以降、DataMapperパターンとDataSourceパターン(または単純なシステムの場合はActiveRecord)が一般的になり、同じ役割を果たしました。ただし、DAOは、永続性に関係するすべてのオブジェクトの流行語になりました。

今日、「DAO」という用語は、悲しいことに「データベースとの通信を可能にするクラス」の同義語になっています。

ORM/JPAを使用すると、真のJ2EE時代のDAOの理論的根拠の多くがすぐに利用できます。

後者のDataSourceパターンの場合、JPAのEntityManagerはDataSourceに似ていますが、通常はPersistenceUnit XML定義を介して提供され、IoCを介してインスタンス化されます。

かつてDAOまたはマッパーに存在していたCRUDメソッドは、リポジトリパターンを使用して1回だけ提供できるようになりました。 AbstractDAOの必要はありません-ORM製品は、Object()を受け入れ、それがどこに永続化されているかを知るのに十分賢いです。

11
8bitjunkie

JDOやJPAなどのORMツールを使用する場合、DAOはアンチパターンです。この場合、「データアクセス層」の作成は完全に不要であり、コードベースに余分なコードと複雑さを追加するだけであり、開発と保守が困難になります。

以前の経験に基づいて、永続性関連の操作に使いやすい高レベルのAPIを提供するために、Persistenceなどの単純な静的ファサードの使用をお勧めします。

次に、静的インポートを使用して、便利な場所でこれらのメソッドに簡単にアクセスできます。たとえば、次のようなコードを作成できます。


    List<Book> cheapBooks = 
        find("select b from Book where b.price < ?", lowPriceForBooks);
    ...
    Book b = new Book(...);
    persist(b);
    ...
    Book existingBook = load(Book.class, bookId);
    remove(existingBook);
    ...

上記のコードは可能な限り簡単でシンプルであり、簡単に単体テストを行うことができます。

6
Rogério

一言:トランザクション

1つのトランザクションで2つのデータ更新操作を実行する必要がある状況を考えてみましょう。これらの操作は一緒になって論理的な作業単位を形成します。私のビジネスロジックは、その作業単位の観点から自分自身を表現したいと考えており、トランザクションの境界に煩わされることを望んでいません。

だから私はDAOを書きます。 Springトランザクションを使用してこの擬似コードを取得し、休止状態にします。

@ Rogerを非常に不快にさせていたが、ポイントに関連していなかったHQLを削除するように編集

@Transactional
public void doUnitOfWork() {
  // some persistence operation here
  // some other persistence operation here
}

私のビジネスロジックはdoUnitOfWork()を呼び出します。これはトランザクションを開始し、両方の永続化操作を実行してからコミットします。トランザクションや実行される操作については、何も知りませんし、気にしません。

さらに、DAOがdoUnitOfWork()メソッドを使用してインターフェイスを実装している場合、ビジネスロジックはインターフェイスにコーディングできるため、単体テストが容易になります。

一般的に、私は常にデータアクセス操作をDAOでラップし、その周りのインターフェイスを叩きます。

6
skaffman

「エンティティごとのDAOクラス」というパターンは、ORM管理のデータレイヤーでは完全に冗長であると思います。代わりに、DAOレイヤーは、任意のエンティティクラスを操作する万能のCRUDメソッドセットのセットと、データに対してより高度な操作を実行する多数のメソッドで構成する必要があります。機能が十分に大きい場合は、ドメイン基準に基づいてDAOレイヤーを複数のクラスに分割する必要があります。これにより、このアプローチはサービス指向アーキテクチャーにより類似したものになります。

3

ほとんどのDAOは、歴史的な(歴史的な;])理由で人々によって追加されていると思います。当初は、ORM以前の日にCRUD操作を実行するために必要なSQL接着剤の便利なカプセル化として意図されていたという点で正しいです。今日では、透過的な永続性により、それらの役割はほとんど冗長になっています。

現在適切なのは、リポジトリとサービスの概念です。

リポジトリ:ORM固有のコード(HibernateやJDOなど)で実装されたクエリメソッドのコレクションを格納するクラス

通常、抽象基本クラスリポジトリを作成してから、ORM固有の実装を提供し、ORMに固有のコードですべてのクエリメソッドを実装できます。このアプローチの優れている点は、MockRepository実装を作成して、DBを使用せずにアプリをテストできることです。

サービス:オブジェクトモデル(通常はORMに依存しないコード)への重要な変更/追加を調整できるメソッドのコレクションを格納するクラス。

これは、アプリをORMからほぼ独立させておくのに役立ちます。アプリを別のORMに移植するには、実際には、新しいORM固有のリポジ​​トリクラスの実装のみが必要です。

3
Volksman

このレイヤーの紹介の目的は、保守性を簡単かつシンプルにすることでした。

  1. データアクセス層
  2. ビジネス層
  3. プレゼンテーション層

第1層(データアクセス層)の目的は、データベースロジックを処理し、ビジネス層がDBの詳細を認識しないようにすることです。
データアクセス層はPOJOまたはEJB(DAO)を使用してIoCを実装し、POJOEJBはHibernateまたはORMマッピングを使用して実際にデータベース層を処理します。
したがって、ビジネスロジックでデータベースがどのように使用され、アクセスされ、更新されているかを気にせず、DAOにこれを処理させたい場合
DAOは、多数の休止状態の呼び出しを行うことにより、操作をサポートするためにさまざまなテーブルを変更するロジックをサポートできます。
本質的には、DAOとHibernateの2つのレイヤーで機能を再び分割することにより、データアクセスレイヤーにレイヤードアプローチを実装しています。

3
user3089214

ORMを使用する場合:透過的な永続性サポートをお楽しみください! ORMAPIをラップするためにDAOを使用しないでください。ここでよく言われているように、DAOはORMの前にあります。 ORMは、透過的永続性や到達可能性による永続性など、OODBMSの概念を導入しました。それはあなたの人生を楽にし、あなたのコードを美しくするので、あなたはそれを利用しなければなりません。部門と従業員をモデル化しているとします... 1つのユースケースは、新しい部門を作成し、新しい従業員を作成し、その従業員を部門に追加することです...あなたはどうしますか?

//start persistence context
...
Department dept1 = new Department("department1");
dept1.addEmployee(new Employee("José", 10503f));

em.persist(dept1);
...
//close persistence context

部門、従業員、およびそれらの関係は現在永続的です。

ここで、既存の従業員を既存の部門に追加する必要があるとします...どうしますか?ものすごく単純:

//start persistence context
...
Department aDepart = hibernateSession.load(Department.class, dId);
Employee anEmployee = hibernateSession.load(Employee.class, eId);

aDepart.addEmployee(anEmployee);     
...
//close persistence context

Hibernate(他のORMと同様)が実装するTransparentPersistenceとPersistencebyReachabilityのおかげで非常にシンプルです。 DAOはまったくありません。

ドメインモデルをコーディングして、メモリに残っているように考えてください。優れたマッピング戦略により、ORMはメモリ内で何を行っているかを透過的に保持します。

その他の例: http://www.copypasteisforword.com/notes/hibernate-transparent-persistencehttp://www.copypasteisforword.com/notes/hibernate-transparent-persistence- ii

1

実際には、これらすべての答えが明らかにするよりも単純でなければなりません。これらのパターンはすべてレイヤーに関するものです。循環参照を使用して、その上のものについてのみ知ることができるレイヤーを作成する必要はありません。 UICodeがすべてのサービスを参照できるようにし、サービスコードがすべてのDAOを参照できるようにする必要があります。

  1. DAO
  2. サービス
  3. UICode

pOJOは上から下に渡されます。

0
andersonbd1