ActiveObjects

昨日のtwitterの内容を
http://d.hatena.ne.jp/yuripop/20080927/p1
で紹介いただいて感動したので、以下を三つについて、コードからわかったことを整理しました。

  • EntityManager.get(Class, K ) 行エンティティを取得する。(キャッシュ管理と生成も行う)
  • EntityManager.find(Class, String, Query) 行を選択とデータのキャッシュ
  • EntityManager.findWithSQL SQLを指定して行エンティティを取得する。

EntityManager.get(Class, K ) 行エンティティを取得する。(キャッシュ管理と生成も行う)

...
// エンティティキャッシュから行エンティティを取得する。
Reference reference = entityCache.get(new CacheKey(key, type));
Reference ref = (Reference) reference;
T entity = (ref == null ? null : ref.get());

// エンティティが取得できたことを確認する:
if (entity != null) {
    // エンティティキャッシュから取得したエンティティを戻り値とする。
    back[index++] = entity;
} else {
    // 取得できない:

    //  エンティティをインスタンス化する。(エンティティキャッシュにも追加。)
    back[index++] = getAndInstantiate(type, key);
}
...

EntityManager.find(Class, String, Query) 行を選択とデータのキャッシュ

...
// クエリからSQLを作成する。
sql = query.toSQL(type, provider, tableNameConverter, getFieldNameConverter(), false);^
...
// SQLを実行し、結果セットを取得する。
ResultSet res = stmt.executeQuery();^M
// 結果セットのメタデータを取得する。
ResultSetMetaData md = res.getMetaData();^M

provider.setQueryResultSetProperties(res, query);

// 選択行ごとに、以下を繰り返す。
while (res.next()) {
    // 行の主キーの値から、エンティティを取得する。
    T entity = get(type, Common.getPrimaryKeyType(type).pullFromDatabase(this, res, Common.getPrimaryKeyClassType(type), field));
    // エンティティーをキーに、データ用キャッシュを取得する。
    CacheLayer cacheLayer = getCache().getCacheLayer(entity);

    // 結果セットのすべての行のデータを、データ用のキャッシュに追加する。
    for (int i = 0; i < md.getColumnCount(); i++) {
        cacheLayer.put(md.getColumnLabel(i + 1), res.getObject(i + 1));
    }

    back.add(entity);
}

    
EntityManager.findWithSQL SQLを指定して行エンティティを取得する。

...
// SQLを実行し、結果セットを取得する。
ResultSet res = stmt.executeQuery();
// 結果セットのすべての行について繰り返す。
while (res.next()) {
    // 行の主キーの値から、エンティティを取得する。
    back.add(get(type, Common.getPrimaryKeyType(type).pullFromDatabase(this, res, (Class) type, keyField)));
}
...

[おまけ]Preloadアノテーション
EntityManager.find(Class, String, Query) 行を選択とデータのキャッシュ

...
// Preloadアノテーションが設定されていることを確認する。
Preload preloadAnnotation = type.getAnnotation(Preload.class);
if (preloadAnnotation != null) {
    // 以下を確認する。
    // ・*指定でない。
    // ・joinでない。
    if (!query.getFields()[0].equals("*") && query.getJoins().isEmpty()) {
        // クエリに新たな選択項目を設定する。

        String[] oldFields = query.getFields();
        List newFields = new ArrayList();

        // Preloadアノテーションに指定された選択項目を、新たな選択項目とする。
        for (String newField : preloadAnnotation.value()) {
            newField = newField.trim();

            int fieldLoc = -1;
            for (int i = 0; i < oldFields.length; i++) {
                if (oldFields[i].equals(newField)) {
                    fieldLoc = i;
                    break;
                }
            }

            if (fieldLoc < 0) {
                newFields.add(newField);
            } else {
                newFields.add(oldFields[fieldLoc]);
            }
        }

        // Preloadアノテーションが"*"が指定された場合、クエリに従来含まれていた選択項目も、新たな選択項目に追加する。
        if (!newFields.contains("*")) {
            for (String oldField : oldFields) {
                if (!newFields.contains(oldField)) {
                    newFields.add(oldField);
                }
            }
        }

        query.setFields(newFields.toArray(new String[newFields.size()]));
    }
}
...