JavaでActiveRecord、てのが気になったので試してみることにした。サポートされているDBはPDFのリファレンスを見ると次の通りだそぅだ。
Supported Databases
Right now our focus is on adding support for as many databases as we can, and jPersist
currently has complete, and fully tested, support for:- MySqlDB2
- Oracle
- Derby
- HSQL
- PostgreSQL
- H2
HSQLDBを使う前提での作業。
- hsqldb/sample.properties
#HSQL Database Engine 1.8.0.7
#Wed Jan 16 03:33:41 GMT+09:00 2008
hsqldb.script_format=0
runtime.gc_interval=0
sql.enforce_strict_size=false
hsqldb.cache_size_scale=8
readonly=false
hsqldb.nio_data_file=true
hsqldb.cache_scale=14
version=1.8.0
hsqldb.default_table_type=memory
hsqldb.cache_file_scale=1
hsqldb.log_size=200
modified=no
hsqldb.cache_version=1.7.0
hsqldb.original_version=1.8.0
hsqldb.compatible_version=1.8.0
- hsqldb/sample.script
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE MEMORY TABLE DEPARTMENTS(DEPARTMENT_ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,NAME VARCHAR(100))
CREATE MEMORY TABLE MEMBERS(MEMBER_ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,DEPARTMENT_ID INTEGER NOT NULL,NAME VARCHAR(100),CONSTRAINT MEMERS_FKEY_01 FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENTS(DEPARTMENT_ID) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 10
SET SCHEMA PUBLIC
非常に横に長いが、整形するとHSQLDBが解析に失敗するのでこのままの状態で。 - src/main/resources/databases.xml
<databases>
<database name="studyJPersist_hsqldb" poolSize="10"
driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:file:hsqldb/sample" />
</databases>
class出力フォルダの直下にあれば良い。eclipseならsrc/databases.xmlになるかな。 - 次にModelをふたつ作成。DEPARTMENTに複数のMEMBERがぶら下がるという関係。まずはDEPARTMENT
package shin1o;
import java.util.Vector;
import jpersist.PersistentObject;
@SuppressWarnings("serial")
public class Department extends PersistentObject {
Long departmentId;
String name;
Vector<Member> members = new Vector<Member>();
public Department() {}
public Department(String _name) { name = _name; }
public String toString() {
return new StringBuilder().append("{id:").append(departmentId).append(
", name:").append(name).append(", members:").append(
members.toString()).append("}}").toString();
}
// Associations
public Vector<Member> getDbAssociation(Member c) {
return members;
}
public void setDbAssociation(Member c, Vector<Member> _members) {
members = _members;
}
public Vector<Member> getMembers() { return members; }
public void setMembers(Vector<Member> members) { this.members = members; }
public Long getDepartmentId() { return departmentId; }
public void setDepartmentId(Long departmentId) { this.departmentId = departmentId; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
- 次にぶら下がる方のMember。
package shin1o;
import jpersist.PersistentObject;
@SuppressWarnings("serial")
public class Member extends PersistentObject {
Long memberId;
String name;
Long departmentId;
public Member() { }
public Member(String _name) { name = _name; }
public String toString() {
return new StringBuilder().append("{id:").append(memberId).append(
", departmentId:").append(departmentId).append(", name:")
.append(name).append("}").toString();
}
public Long getMemberId() { return memberId; }
public void setMemberId(Long memberId) { this.memberId = memberId; }
public String getName() { return name; }
public void setName(String _name) { this.name = _name; }
public Long getDepartmentId() { return departmentId; }
public void setDepartmentId(Long departmentId) { this.departmentId = departmentId; }
}
- TestClassを作成して、動作確認をしてみる。
package shin1o;
import static org.junit.Assert.assertEquals;
import java.util.*;
import jpersist.*;
import org.junit.*;
public class JPersistTest {
static DatabaseManager dbm;
@BeforeClass
public static void setUp() throws JPersistException {
DatabaseManager.setLogLevel(java.util.logging.Level.INFO);
dbm = DatabaseManager
.getXmlDefinedDatabaseManager("studyJPersist_hsqldb");
}
@AfterClass
public static void tearDown() throws JPersistException {
if (dbm != null && !dbm.isClosed()) {
dbm.close();
}
}
/**
* {@link #before()} で作成したDepartmentのidを毎回保存しておく。
*/
Long d0Id, d1Id, d2Id;
/**
* Testするたびに初期データを作り直す。
* @throws Exception
*/
@Before
public void before() throws Exception {
Department d0 = new Department("department0");
d0.save(dbm);
d0Id = d0.getDepartmentId(); // save後にIDを保存。
Department d1 = new Department("department1");
d1.getMembers().add(new Member("member_1_1"));
d1.getMembers().add(new Member("member_1_2"));
d1.getMembers().add(new Member("member_1_3"));
d1.save(dbm);
d1Id = d1.getDepartmentId();
Department d2 = new Department("department2");
d2.getMembers().add(new Member("member_2_1"));
d2.getMembers().add(new Member("member_2_2"));
d2.save(dbm);
d2Id = d2.getDepartmentId();
}
@After
public void after() throws Exception {
// 全部消す
Result<Department> departments = dbm.getDatabase().queryObject(
Department.class);
while (departments.hasNext()) {
Department department = departments.next();
dbm.getDatabase().deleteObject(department);
}
}
@Test
public void 一件load_ClassとSql条件() throws Exception {
Department department = dbm.loadObject(Department.class,
"where :departmentId = '" + d1Id + "'");
assertEquals(d1Id, department.getDepartmentId());
assertEquals(3, department.getMembers().size());
}
@Test
public void 一件load_ClassとSql条件とパラメタ() throws Exception {
Department department = dbm.loadObject(Department.class,
"where :name like ?", "%1");
assertEquals(d1Id, department.getDepartmentId());
}
@Test
public void 一件load_Object() throws Exception {
Department department = dbm.loadObject(new Department("%1"));
assertEquals(d1Id, department.getDepartmentId());
}
@Test
public void 全件取得() throws Exception {
Collection<Department> departments = dbm.loadObjects(
new ArrayList<Department>(), Department.class);
assertEquals(3, departments.size());
Collection<Member> members = dbm.loadObjects(new ArrayList<Member>(),
Member.class);
assertEquals(5, members.size());
}
@Test
public void 複数件load_ClassとSql条件とパラメタ() throws Exception {
Collection<Department> departments = dbm.loadObjects(
new ArrayList<Department>(), Department.class,
"where :name like ?", "dep%");
assertEquals(3, departments.size());
}
@Test
public void transactionManagerを使う() throws Exception {
TransactionManager transaction = new TransactionManager(dbm) {
Collection<Department> departments;
final String sql = "where :name like 'dep%'";
public void run() throws JPersistException { // 最初は3件。
departments =
dbm.loadObjects(new ArrayList<Department>(), Department.class,
sql);
assertEquals(3, departments.size());
new Department("department_a").save(this);
commit(); // 1件追加したから4件のはず。
departments = loadObjects(Department.class, sql);
assertEquals(4, departments.size());
new Department("department_b").save(this); // さらに1件追加したから5件のはず。
departments = loadObjects(Department.class, sql);
assertEquals(5, departments.size());
rollback(); // rollbackしたから4件のはず。
departments = loadObjects(Department.class, sql);
assertEquals(4, departments.size());
}
};
transaction.executeTransaction();
}
@Test
public void 一件delete() throws Exception {
Department department = dbm.loadObject(Department.class,
"where :departmentId = '" + d2Id + "'");
dbm.deleteObject(department);
Collection<Department> departments = loadObjects(Department.class);
assertEquals(2, departments.size()); // delete cascadeでmemberも減っているはず。
Collection<Member> members = loadObjects(Member.class);
assertEquals(3, members.size());
}
<T> Collection<T> loadObjects(Class<T> c) throws JPersistException {
return dbm.loadObjects(new ArrayList<T>(), c);
}
<T> Collection<T> loadObjects(Class<T> c, String sql)
throws JPersistException {
return dbm.loadObjects(new ArrayList<T>(), c, sql);
}
}
サンプルを元に単純な例を試すとこんなカンジに使うことになる。ModelがPOJOでないのが引っかかるけど、かなり簡単。Modelに[「get|set]Associations()」を追加するのがポイント。
ちなみに、注意点として「Modelにプリミティブな型を使わない」といぅこと!プリミティブな型はnullを表現できないため、自動的に関連先を取得する時のSQLの条件にプリミティブなフィールドが含まれていまい、正しく関連先が取得できません!俺ハマったよ!
この状態で、SingleTableInheritanceを試そうとしたけど、PDFのドキュメントにある「jpersist.interface.SingleInheritance」が存在しなかったりで苦戦中。また後日チャレンジする。
0 件のコメント:
コメントを投稿