平々毎々(アーカイブ)

はてなダイアリーのアーカイブです。

JavaのいろんなORMのクエリとLINQを見比べる

id:masanobuimaiに紹介してもらった後でナニだけど、はてなに移動。

Java屋さんとC#屋さんの両方向け。Java屋さんは「へー、LINQってこういうことなのね」と思ってくれれば。C#屋さんは「へー、ORMっていろいろあるんだね」と思ってくれれば。

(追記)CayenneActiveObjectsを入れておけばよかったかな。

Criteriaクラスを使う (Torque)

Torqueの場合、問い合わせは各エンティティのPeerクラスに対して行う。Criteriaクラスで条件指定。Criteria.CUSTOMを使えば条件部を文字列で書ける。あと、Criteriaを使ってJOINもできる。

ただ、いわゆる「流れるようなインターフェース」ではないので、コードが少々めんどくさい。

Criteria criteria = new Criteria();
criteria.add(EmpPeer.EMPNO, (Object)"999", GREATER_THAN);
List list = EmpPeer.doSelect(criteria);
SQLとDAOのメソッドとを対応付ける (iBatisS2Daoなど)

SQLを書いておいて、コードからはそれに対応するメソッドを呼び出す。ADO.NETで言えばTableAdapterの使用感に近い。SQLおよびマッピングの置き場所は、iBatisなら設定ファイル、S2Daoならアノテーション

TableAdapterと一緒で、SQLが書けないとどうしようもない。また、SQLマッピングを手で書くのが少々面倒かもしれない。TableAdapterはツール(Visual Studio)が支援してくれる。S2Daoアノテーションなど工夫されている。

コード例はS2Dao

EmpDao dao = (EmpDao)container.getComponent(EmpDao.class);
List<Emp> list = dao.getEmpListWhereEmpNoGreaterThan(999);
埋め込み外部DSL (JPAHibernateなど)

JPAではEJB QLJPQL、HibernateではHQLという埋め込み外部DSLを文字列で渡す。

よくできているし強力だ(いろんなことができる)が、全部文字列なので型安全ではない。

コード例はJPA

Query query = entityManager.createQuery
    ("SELECT OBJECT(emp) FROM Emp emp WHERE emp.empNo > :empNo");
query.setParameter("empNo", 999);
List list = query.getResultList();
内部DSL (S2JDBCJEQUELLIQUidFORMJaQuSquillなど)

流れるようなインターフェース」でかつ型安全。もっともLINQのメソッド形式に近い。ただ、選択やソートの条件をどうするかは悩ましいところ。

  • "EMPNO > ?"みたいな文字列で渡す
  • 内部的に式木のようなものを保持する条件クラスのインスタンスとして渡す

前者だと型安全ではない(許容範囲?)。後者でnewとか書くのがいやだというときには、ヘルパーメソッドを使うことになるのだと思う。

ここはまだメジャーなプロダクトがない状態だと理解しているけど、あってんのかな。教えてえらい人。

コード例はS2JDBC

List<Emp> list = jdbcManager.from(Emp.class)
                            .where(new SimpleWhere()
                                .gt("EMPNO", 999))
                            .getResultList();
LINQ

流れるようなインターフェースでも書けるし、クエリ式でも書ける。シンタックスシュガーwwやりすぎww

条件部はラムダ式。しかも、ラムダ式は式木(Expression Tree)としてコンパイルされ、実行時にSQLに変換される。型安全wwやりすぎww

コード例はADO.NET Entity Framework + LINQ

List<Emp> list;
using (MyDBContext context = new MyDBContext())
{
    list = context.Emps
               .Where(x => x.EmpNo > 999)
               .ToList();
}

LINQやりすぎwwと書いたけど、意図があってこういうデザインになっていることは理解しておきたい。

たとえば式木。LINQはデータベース専用のクエリではないので、極力汎用的な形で条件を保持しておかなければならない。

たとえばクエリ式。複雑なクエリ(たとえば直積のように、メソッド形式だとSelectManyを使わないといけないようなクエリ)などはどうしても分かりやすく書けず、プログラマーに対する負荷が大きい。