4

私が取り組んでいる現在のアプリケーションは大きなものです。データベースは 300 以上のテーブルで構成されており、その数は増え続けています。現時点ではデスクトップ アプリケーションですが、Web に移行しています。

これに使用しているテクノロジーは、Spring (MVC) + バックエンドの Hibernate とフロントの ZK フレームワークです。データベースに 300 以上のテーブルがあり、その数の POJO も作成することになりました。Spring の DAO パターンを使用すると、プロジェクトには 300 以上の DAO オブジェクトと 300 以上のサービス クラスが必要になります。

これは私が現時点でやっている方法です:

ポジョ:

@Entity
@Table(name="test")
public class Test implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    private Integer version;

    private String m_name;


    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="jpa_id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Version
    @Column(name="jpa_version", insertable=false, updatable=false)
    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    @Column(name="name", length=30)
    public String getM_name() {
        return m_name;
    }

    public void setM_name(String m_name) {
        this.m_name = m_name;
    }
}

DAO オブジェクトのインターフェース:

public interface IDao<T> {
    public List<T> getAll();
}

コピー/貼り付けを避けるために、すべての DAO オブジェクトによって拡張される汎用 DAO クラスを作成しました。

@Repository
public class GenericDAO<T extends Serializable> implements IDao<T> {

    @Autowired
    protected SessionFactory sessionFactory;

    protected Class<T> entity;

    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        List<T> result = (List<T>) getSessionFactory().getCurrentSession().createQuery("from " + entity.getName()).list();
        return result;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void setEntity(Class<T> entity) {
        this.entity = entity;
    }
}

DAO オブジェクト:

@Repository
public class TestDAO extends GenericDAO<Test> {

    public TestDAO() {
        setEntity(Test.class);
    }   
}

サービス インターフェイス:

public interface IService<T> {
    public List<T> getAll();
}

サービスの実装:

@Service
public class TestService implements IService<Test> {

    @Autowired
    private IDao<Test> testDAO;

    @Transactional(readOnly=true)
    public List<Test> getAll() {
        return testDAO.getAll();
    }

    public void setTestDAO(IDao<Test> testDAO) {
        this.testDAO = testDAO;
    }
}

2 つの質問があります。

  1. c/p を回避するために、上記の GenericDAO クラスのような汎用サービスを作成するにはどうすればよいですか?

  2. DAO の実装を見ると、コンストラクターしかありません。すべてのPOJOを処理する「1つの」DAOクラスと、すべて/1つのDAOオブジェクトを処理する1つのサービスクラスを持つ方法はありますか?

4

3 に答える 3

4

質問1

これはあなたの質問に対する正確な回答ではありませんが、ご容赦ください...

Spring の DAO パターンを使用すると、プロジェクトには 300 以上の DAO オブジェクトと 300 以上のサービス クラスが必要になります。

これはよくある誤解であり、間違っています。

まず第一に、300 以上のテーブルがすべて互いに独立している可能性はほとんどありません。おそらく、これらのテーブルの多くは、1-1、1 - n、およびn - m の関係を提供します。このような場合は、関係の所有部分にのみ DAO を使用することをお勧めします。他の部分は、JPA のカスケード機能を使用して保存および取得する必要があります。

さらに、サービス層は、DAO の上に余分な無関係な層として意図されているわけではありません。これは、ユーザーによる各アクションがサービス層の 1 つのメソッドに正確にマッピングされる、統一された概念ドメイン モデルを提供することを目的としています。

次の例を見てみましょう。

authorbookおよびの 3 つのテーブルがありchapterます。と の間には 1- nの関係がbookありchapter、 と の間にはnmの関係がbookありauthorます。この例では、著者と書籍は強力なエンティティと見なされますが、章は弱いエンティティと見なされます (それらの存在は書籍の存在に依存します)。

この例では、実際に 3 つの JPA アノテーション付き POJO があります。ただし、 DAO はとの2 つしかありません。章へのすべてのアクセスは を経由する必要があるため、はありませんAuthorDAOBookDAOChapterDAOBookDAO

interface BookDAO {
    findAll();
    findById(BookID id)

    saveBook(Book book);
    addChapter(BookID id, Chapter chapter); 
    // etcetera
}

次に、例の最終的な目標を見てみましょう。新しい本の RSS フィードを提供するアプリケーションだとしましょう。新しい本を追加するための管理者インターフェースもあります。

この場合、2 つの Service クラスを取得しますが、DAO とはまったく関係ありません。

interface RssService {
    Collection<Book> getRecentBooks();
}

interface AdminService {
    addBook(AddBookCommand cmd);
    addAuthor(AddAuthorToBookCommand cmd);
}

私が主張する最後の点は論点であり、他の人は私に反対するでしょう. 現在の AdminService には、システム内のすべての書籍のリストを提供する手段がありません。これを解決するには、次の 2 つのオプションがあります。

  • getAllBooksgetAllAuthorsメソッドを に追加 しますAdminService
  • ビューで既存の DAO を使用するだけです。

私は後者を好みますが、前述のように、他の人はこれに同意しません。

ただし、これらのサービスをどのように実装しても、DAO とは直接関係がないことに注意してください。

そして今、私はあなたの質問に完全に答えることができます:

c/p を回避するために、上記の GenericDAO クラスのような汎用サービスを作成するにはどうすればよいですか?

あなたはそうしない。汎用サービスは、サービス層を持つという目的全体を無効にします。

質問2

DAO の実装を見ると、コンストラクターしかありません。すべての POJO を処理する「1 つの」DAO クラスを持つ方法はありますか

はい、しかしもう一度お勧めします。最初は、DAO は同じかもしれませんが、プロジェクトが進行するにつれて、DAO は特殊化され、特定のメソッドが必要になります。例えば:

interface BookDAO {
    // generic stuff
    ...
    // end generic stuff
    getBooksWithMinimumChapters(int minimumChapterCount);
}

interface AuthorDAO {
    // generic stuff
    ...
    // end generic stuff

    getAuthorsWithMultipleBooks(int minimalBookCount); 
}

したがって、今のところ、単一のコンストラクターと一連のジェネリック継承メソッドをそのままにしておきます。

于 2012-11-13T12:17:56.223 に答える
3

Spring Data プロジェクト、特にDAO クラスを劇的に簡素化する可能性のあるSpring-Data-JPAを詳しく調べることをお勧めします。これはCrudRepositoryJpaRepositoryを提供し、ほとんどの場合、必要な機能をすべて備えています。さらに必要な場合は、いつでも独自のクエリを作成し、標準インターフェイスを拡張できます。

さらにいくつかのアイデア:データベースからエンティティを生成し、DAO クラスを生成します。

于 2012-11-13T11:50:28.360 に答える
2

質問への回答:

DAO の実装を見ると、コンストラクターしかありません。すべてのPOJOを処理する「1つの」DAOクラスと、すべて/1つのDAOオブジェクトを処理する1つのサービスクラスを持つ方法はありますか?

リフレクションを使用して、ジェネリックのパラメーター化された型を取得できます。これにより、作成する必要があるオブジェクトの量を減らすことができます。

@Repository
public class GenericDAO<T extends Serializable> implements IDao<T> {

    @Autowired
    protected SessionFactory sessionFactory;

    protected Class<T> entity;

    public GenericDao(){
      ParameterizedType genericSuperClass = (ParameterizedType) getClass().getGenericSuperclass();
      this.entity = (Class<T>) genericSuperClass.getActualTypeArguments()[0];
    }

    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        List<T> result = (List<T>) getSessionFactory().getCurrentSession().createQuery("from " + entity.getName()).list();
        return result;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void setEntity(Class<T> entity) {
        this.entity = entity;
    }
}
于 2012-11-13T11:50:56.860 に答える