web-dev-qa-db-ja.com

DAO vs ORM(hibernate)パターン

いくつかの記事を読んで、DAOは休止状態では必須ではなく、その実装は「依存する」ことです。言い換えれば、ORMとDAOのどちらのパターンを選択することができます。

OK、DAOパターンを使用したくないと仮定しましょう。セッションCRUDとhibernate(my ORM)が提供するクエリ操作のみを使用します。

特に、「検索」クエリと「検索」クエリの場合、クエリを常に書き換えるのは正しくないため、それらをクラスに入れることは理にかなっています。

しかし、このクラスは、DAOパターンとDAOFactoryのすべての実装を持たない単純なDAOであり、DAOの軽量実装のみです。だから、ポイントは常にDAOが必要であり、選択は重いDAO実装対軽量DAO実装であるということですか?

私が言ったことは間違っていますか?

[〜#〜] edit [〜#〜]私が持っている別の問題は、daoインタラクションを置く場所です。たとえば、ユーザーにログインし、ログインのログを書き込む必要があります(役に立たない例です。 )

したがって、DAOパターンには、すべての汎用dao実装、DAOFactory、最後にUserHibernateDAOおよびLogHibernateDAOがあります。ログイン操作はビジネスメソッドです。

private void login(String username, String password){
    daoFactory.beginTransaction();
    UserDAO userDao=daoFactory.HIBERNATE.getUserDao();
    LogDAO logDao=daoFactory.HIBERNATE.getLogDao();
    if(userDao.checkAccount(username, password){
        User user=userDao.findByAccount(username, password);
        logDao.save(new Log("log-in", user);
    }
    daoFactory.commit();
}

これは合理的ですか? daoをこのように使用できますか?例外を処理したい場合、それを行うより良い場所はビジネスロジックですか?

EDIT2 DAOパターンを使用すると仮定します。これを行う主な理由は、技術(ORM-> JDBCなど)を切り替えることができることです。休止状態のセッションとトランザクションを処理しますか?私はそれをDAOに入れることができません、それはアンチパターンです、そして私はそれをサービス層に入れることができません、なぜなら私はこのトランザクションをすべて削除する必要があるためです(他の技術はそれらを使用しないかもしれないので)。

45
blow

ORMとDAOは直交する概念です。 1つはオブジェクトをデータベーステーブルにマップする方法に関係し、もう1つはデータにアクセスするオブジェクトを記述するためのデザインパターンです。それらの「間」を選択しないでください。 ORMを使用でき、DAOパターンを使用するためにORMを必要としないのと同じように、DAOは同じアプリケーションです。

つまり、実際にはneed何もすることはありませんが、DAOを使用する必要があります。このパターンは、モジュール化されたコードに役立ちます。すべての永続化ロジックを1つの場所に保持します(懸念の分離、漏れやすい抽象化との戦い)。アプリケーションの他の部分とは別にデータアクセスをテストできます。そして、データアクセスから隔離されたアプリケーションの残りの部分をテストできるようにします(つまり、DAOをモックできます)。

さらに、データアクセスの実装が困難な場合でも、DAOパターンに従うのは簡単です。そのため、コストは非常に少なく(またはゼロ)、多くの利益が得られます。

EDIT-あなたの例に関しては、ログインメソッドは何らかのAuthenticationServiceである必要があります。そこで、ログインメソッドで例外を処理できます。 Springを使用した場合、(1)トランザクション、(2)依存性注入など、多くのことを管理できます。独自のトランザクションやdaoファクトリを記述する必要はありません。サービスメソッドの周りのトランザクション境界を定義し、DAO実装をbeanとして定義してからサービスにワイヤリングできます。

EDIT2

パターンを使用する主な理由は、懸念を分離することです。つまり、永続化コードはすべて1か所にあります。これの副作用は、テスト可能性と保守容易性です。これにより、後で実装を簡単に切り替えることができます。 HibernateベースのDAOを構築している場合、DAOでセッションを絶対に操作できます。アンチパターンは、永続性に関連するコードが永続層の外側で発生する場合(漏れやすい抽象化の法則)です。

トランザクションは少し複雑です。一見、トランザクションは永続性の懸念のように思えるかもしれませんが、そうです。しかし、それらは永続性の問題だけではありません。トランザクションもサービスの懸念事項です。サービスメソッドは「作業単位」を定義する必要があります。つまり、サービスメソッドで発生するすべてがアトミックである必要があります。休止状態のトランザクションを使用する場合は、DAOの外部で休止状態のトランザクションコードを記述し、多くのDAOメソッドを使用するサービスの周囲にトランザクション境界を定義する必要があります。

ただし、トランザクションは実装に依存しないことに注意してください。休止状態を使用するかどうかにかかわらず、トランザクションが必要です。また、休止状態のトランザクションメカニズムを使用する必要がないことに注意してください。コンテナベースのトランザクション、JTAトランザクションなどを使用できます。

Springなどを使用しないと、トランザクションが苦痛になることは間違いありません。 Springを使用してトランザクションを管理するか、I believeを使用してアノテーションを使用してサービスの周りにトランザクションを定義できるEJB仕様を使用することをお勧めします。

コンテナベースのトランザクションについては、次のリンクをご覧ください。

コンテナ管理トランザクション

セッションとトランザクション

これから収集しているのは、サービスレベルでDAOの外部のトランザクションを簡単に定義でき、トランザクションコードを記述する必要がないということです。

別の(エレガントではない)代替方法は、すべてのアトミックな作業単位をDAO内に配置することです。単純な操作のためにCRUD DAOを作成し、複数のCRUD操作を行うより複雑なDAOを作成することができます。このようにして、プログラムトランザクションはDAOにとどまり、サービスはより複雑なDAOを呼び出し、トランザクションを心配する必要がなくなります。

次のリンクは、DAOパターンがコードの簡素化にどのように役立つかを示す良い例です

AO vs ORM(hibernate)pattern

(thanx @ daff

インターフェイスの定義がどのようにしてインターフェイスを作成し、ビジネスロジックがUserDaoの動作のみを考慮するようにするかに注意してください。実装は気にしません。休止状態または単にJDBCを使用してDAOを作成できます。したがって、プログラムの残りの部分に影響を与えることなく、データアクセスの実装を変更できます。

75
hvgotcodes

ソースコードの例をhvgotcodesの良い答えに提供させてください。

public class Application
{
    private UserDao userDao;

    public Application(UserDao dao)
    {
        // Get the actual implementation
        // e.g. through dependency injection
        this.userDao = dao;
    }

    public void login()
    {
        // No matter from where
        User = userDao.findByUsername("Dummy");
    }
}


public interface UserDao
{
    User findByUsername(String name);
}

public class HibernateUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do some Hibernate specific stuff
        this.session.createQuery...
    }
}

public class SqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        String query = "SELECT * FROM users WHERE name = '" + name + "'";
        // Execute SQL query and do mapping to the object
    }
}

public class LdapUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Get this from LDAP directory
    }
}

public class NoSqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do something with e.g. couchdb
        ViewResults resultAdHoc = db.adhoc("function (doc) { if (doc.name=='" + name + "') { return doc; }}");
        // Map the result document to user
    }
}

したがって、既に述べたように、DAOはアプリケーションとバックエンドの間のカップリングを最小限に抑える設計パターンです。一方、ORMはオブジェクトをオブジェクトリレーショナルデータベースにマッピングする方法を処理します(これにより、データベースとアプリケーション間のカップリングが減少しますが、 DAOを使用しない場合、アプリケーションは使用するORMまたは上位レベルのJPAなどの標準に依存します)。

したがって、DAOがなければ、アプリケーションを変更することは非常に困難です(たとえば、JPA互換のORMではなくNoSQLデータベースに移行する)。

30
Daff

いいえ、それは正しいとは思いません。 ORMは、DAOを実装する1つの方法です。 ORMなしでDAOを実行することを選択できます。

あなたはそれを後方に持っています:依存関係が大きいので、私はORMがDAOより重いと考えます。 ORMを使用せずにストレートJDBCでDAOを作成できます。それは軽く、IMOです。

同意するかどうかは、「軽い」と「重い」をどのように定義するかによります。私は依存関係で行きます-JDK自体の上に必要な追加のJARの数。

12
duffymo