package jef.database.dynamic; import java.io.File; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import jef.database.Condition.Operator; import jef.database.DbClient; import jef.database.NativeQuery; import jef.database.QB; import jef.database.RecordHolder; import jef.database.RecordsHolder; import jef.database.VarObject; import jef.database.dialect.ColumnType; import jef.database.meta.TupleMetadata; import jef.database.query.Func; import jef.database.query.Join; import jef.database.query.Query; import jef.database.query.Selects; import jef.database.test.DataSource; import jef.database.test.DataSourceContext; import jef.database.test.DatabaseDestroy; import jef.database.test.DatabaseInit; import jef.database.test.IgnoreOn; import jef.database.test.JefJUnit4DatabaseTestRunner; import jef.orm.onetable.model.TestEntity; import jef.script.javascript.Var; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; /** * 这个类测试动态表的创建、单表操作、批操作、查询、删除、表修改等功能 * * @author jiyi * */ @RunWith(JefJUnit4DatabaseTestRunner.class) @DataSourceContext({ @DataSource(name="oracle",url="${oracle.url}",user="${oracle.user}",password="${oracle.password}"), @DataSource(name = "mysql", url = "${mysql.url}", user = "${mysql.user}", password = "${mysql.password}"), @DataSource(name="postgresql",url="${postgresql.url}",user="${postgresql.user}",password="${postgresql.password}"), @DataSource(name="derby",url="jdbc:derby:./db;create=true"), @DataSource(name = "hsqldb", url = "jdbc:hsqldb:mem:testhsqldb", user = "sa", password = ""), @DataSource(name = "sqlite", url = "jdbc:sqlite:test.db?date_string_format=yyyy-MM-dd HH:mm:ss"), @DataSource(name = "sqlserver", url = "${sqlserver.url}",user="${sqlserver.user}",password="${sqlserver.password}") }) @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class DynamicTableTest extends org.junit.Assert { private DbClient db; private TupleMetadata meta; private TupleMetadata GroupTable; /** * 添加了@DatabaseInit注解的方法将在每次连接到数据库后执行。 * @throws SQLException */ @DatabaseInit public void prepareTable() throws SQLException { db.dropTable(meta); db.dropTable(GroupTable); db.createTable(meta); db.createTable(GroupTable); } /** * 添加了@DatabaseDestroy註解的方法在每次数据库关闭时执行 */ @DatabaseDestroy public void destoryTable(){ } public DynamicTableTest(){ meta = new TupleMetadata("URM_SERVICE_1"); meta.addColumn("id", new ColumnType.AutoIncrement(8)); meta.addColumn("name", new ColumnType.Varchar(100)); meta.addColumn("pname", new ColumnType.Varchar(100)); meta.addColumn("flag", new ColumnType.Boolean()); meta.addColumn("photo", new ColumnType.Blob()); meta.addColumn("groupid", new ColumnType.Int(10)); // meta.addIndex("pname", "unique"); // meta.addIndex(new String[]{"groupid","pname","name","flag"}, "unique"); GroupTable = new TupleMetadata("URM_GROUP"); GroupTable.addColumn("id", new ColumnType.AutoIncrement(8)); GroupTable.addColumn("serviceId", new ColumnType.Int(8)); GroupTable.addColumn("name", new ColumnType.Varchar(100)); GroupTable.addCascadeOneToMany("services", meta, QB.on(GroupTable.f("id"),meta.f("groupid"))); } @Test public void test1Tuple(){ TupleMetadata meta=new TupleMetadata("asdf"); meta.addColumn("aa", new ColumnType.AutoIncrement(10)); meta.getAllColumnNames(); meta.getColumns(); meta.removeColumn("aa"); System.out.println(meta); } /** * 测试插入记录到动态表 * @throws SQLException */ @Test public void test2Insert() throws SQLException { try{ doInsert(); }catch(SQLException e){ e.printStackTrace(); throw e; } } private int doInsert() throws SQLException { VarObject obj = new VarObject(meta); obj.put("name", "MyName is Jiyi"); obj.put("pname", "assa"); obj.put("flag", false); obj.put("photo", new File("c:/bootmgr"));//将本地文件存入BLOB db.insert(obj); return (Integer) obj.get("id"); } /** * 测试批量插入动态表 * @throws SQLException */ @Test public void test3InsertBatch() throws SQLException { File file=null; file=new File("c:/bootmgr"); if(!file.exists()){ file=null; throw new IllegalArgumentException("测试用的本地文件没有找到!"); } VarObject obj1 = meta.newInstance(); obj1.put("name", "My Name is Jiyi"); obj1.put("pname", "assa"); obj1.put("flag", false); obj1.put("photo", file); VarObject obj2 = meta.newInstance(); obj2.put("name", "My Name is Jiyi"); obj2.put("pname", "assa"); obj2.put("flag", false); obj2.put("photo", file); VarObject obj3 = meta.newInstance(); obj3.put("name", "My Name is Jiyi"); obj3.put("pname", "assa"); obj3.put("flag", false); obj3.put("photo", file); VarObject obj4 = meta.newInstance(); obj4.put("name", "My Name is Jiyi"); obj4.put("pname", "assa"); obj4.put("flag", false); obj4.put("photo", file); db.batchInsert(Arrays.asList(obj1, obj2, obj3, obj4)); } /** * 测试更新动态表 * @throws SQLException */ @Test public void test4Update() throws SQLException { int id = doInsert(); VarObject obj1 = meta.newInstance(); obj1.set("id", id); VarObject obj2 = db.load(obj1); System.out.println(obj2); obj2.set("name", "XFire"); db.update(obj2); } /** * 测试批量更新动态表 * @throws SQLException */ @Test public void test5UpdateBatch() throws SQLException { test2Insert(); List<VarObject> result = db.select(QB.create(meta)); System.out.println(result.size()); int n = 0; for (VarObject element : result) { element.set("name", "test" + n++); } db.batchUpdate(result); } /** * 测试删除记录 * @throws SQLException */ @Test public void test6Remove() throws SQLException { test2Insert(); List<VarObject> result = db.select(QB.create(meta)); if (result.size() > 0) { db.delete(result.get(0)); } int deleted = db.delete(QB.create(meta)); assertTrue(deleted > 0); } /** * 测试批量删除记录 * @throws SQLException */ @Test public void test7RemoveBatch() throws SQLException { test3InsertBatch(); List<VarObject> result = db.select(QB.create(meta)); db.executeBatchDeletion(result); } /** * 测试NativeQuery * @throws SQLException */ @Test public void test8SelectNativeQuery() throws SQLException { test3InsertBatch(); NativeQuery<VarObject> q= db.createNativeQuery("select * from URM_SERVICE_1", meta); List<VarObject> result = q.getResultList(); VarObject first=result.get(0); System.out.println(first); } /** * 测试选出记录,并直接在游标上修改 (单条) * @throws SQLException */ @Test // @IgnoreOn({"sqlite","sqlserver"}) @IgnoreOn(allButExcept="postgresql") public void test9LoadForUpdate() throws SQLException { int id = doInsert(); VarObject var = meta.newInstance(); var.set("id", id); RecordHolder<VarObject> holder = db.loadForUpdate(var); holder.get().set("name", "呵呵"); holder.commit(); holder.close(); var = db.load(var); assertEquals(var.get("name"), "呵呵"); } /** * 测试选出记录,并直接在游标上修改 (多条) * 包括在游标上直接创建新记录, 以及删除就记录 * @throws SQLException * MySQL测试去除,See #73 */ @Test @IgnoreOn({"sqlite","sqlserver","mysql"}) public void testaSelectForUpdate() throws SQLException { doInsert(); doInsert(); int max=doInsert(); RecordsHolder<VarObject> holder = db.selectForUpdate(QB.create(meta), null); try{ int n = 0; //更新数据 for (VarObject var : holder.get()) { var.set("name", "更新字段" + n++); } //插入一条记录 if(holder.supportsNewRecord()){ VarObject insert=holder.newRecord(); // insert.set("id", ++max); insert.set("name", "新插入的记录"); } holder.commit(); // 提交,但不关闭结果集 // 继续修改 for (VarObject var : holder.get()) { holder.delete(var); } holder.commitAndClose(); List<VarObject> result = db.select(QB.create(meta)); System.out.println("Size=" + result.size()); assertEquals(result.size(), holder.supportsNewRecord()?1:0); //之前查出的记录全部被删除,只剩下新插入的记录卡了 //打印出操作后的全部记录 for (VarObject var : result) { System.out.println(var.get("name")); } //进一步测试:之前测试发现在Derby上,在执行完此次操作后执行insert操作,会出现主键冲突,因此加以测试 doInsert(); }finally{ holder.close(); } } /** * 测试修改表结构,在表中添加两个字段 * @throws SQLException */ @Test @IgnoreOn({"sqlite","sqlserver"}) public void testbAlterTable_AddColumn() throws SQLException { meta.addColumn("addColumn1", new ColumnType.Date()); meta.addColumn("addColumn2", new ColumnType.TimeStamp().notNull().defaultIs(Func.now)); try { db.refreshTable(meta,ps); } catch (SQLException e) { e.printStackTrace(); throw e; } } @Test @IgnoreOn(allButExcept="sqlite") public void testcAlterTable_AddColumn_forSqlite() throws SQLException { meta.addColumn("addColumn1", new ColumnType.Date()); meta.addColumn("addColumn2", new ColumnType.TimeStamp()); try { db.refreshTable(meta,ps); } catch (SQLException e) { e.printStackTrace(); throw e; } } /** * 测试修改表结构,在表中删除字段 * @throws SQLException */ @Test public void testdAlterTable_RemoveColumn() throws SQLException { meta.removeColumn("flag"); meta.removeColumn("photo"); try { db.refreshTable(meta,ps); } catch (SQLException e) { e.printStackTrace(); throw e; } } // private ProgressSample ps=new ProgressSample(); private ProgressSample ps=null; /** * 测试修改表结构,变更字段的类型,延长varchar长度,并且设置为not null * @throws SQLException */ @Test public void testeAlterTable_ChangeColumn() throws SQLException { meta.updateColumn("flag1", new ColumnType.Boolean()); meta.updateColumn("name", new ColumnType.Varchar(200).notNull()); try { db.refreshTable(meta,ps); } catch (SQLException e) { e.printStackTrace(); throw e; } } /** * 测试其他单表查询 * @throws SQLException */ @Test public void testfFreeConditionQuery() throws SQLException{ this.prepareTable(); doInsert(); Query<VarObject> q=QB.create(meta); q.addCondition(meta.f("name"), Operator.MATCH_START,"MyName"); List<VarObject> list=db.select(q); assertTrue(list.size()>0); } /** * 测试两张动态表关联查询 * @throws SQLException */ @Test public void testg2TableJoin() throws SQLException{ db.truncate(meta); db.truncate(GroupTable); //准备数据 try{ int key1=doInsert(); VarObject group=GroupTable.newInstance(); group.set("serviceId", key1); group.set("name", "We are about to make all these cases be fine"); db.insert(group); System.out.println(group.get("id"));//得到t2的自增主键 //开始 Query<VarObject> t1=QB.create(meta); Query<VarObject> t2=QB.create(GroupTable); t2.addCondition(GroupTable.f("name"),Operator.MATCH_ANY ,"these cases"); Join join=QB.leftJoin(t1, t2, QB.on(meta.f("id"), GroupTable.f("serviceId"))); Selects select=QB.selectFrom(join); select.allColumns(t1); select.column(GroupTable.f("id")); select.sqlExpression("t1.name || t2.name").as("MyColumn"); List<Var> object=db.selectAs(join, Var.class); assertTrue(object.size()>0); Var obj=object.get(0); System.out.println(obj); assertEquals("MyName is JiyiWe are about to make all these cases be fine",obj.get("MyColumn")); System.out.println(object); }catch(SQLException e){ e.printStackTrace(); throw e; } } /** * 测试两个动态之间存在1对多关系时的级联操作 * @throws SQLException */ @Test public void testhCascade1vN() throws SQLException{ db.delete(QB.create(meta)); int id; { /** * 级联插入 */ VarObject group=GroupTable.newInstance(); group.set("name", "My Group 1"); group.set("services", Arrays.asList(meta.newInstance().set("name", "service1"),meta.newInstance().set("name", "service2"))); db.insertCascade(group); id=(Integer)group.get("id"); System.out.println("新插入的group对象id为:"+id); //查询时即检查数据 } { /** * 级联查询 */ VarObject group=db.load(GroupTable.newInstance().set("id", id)); assertEquals(id, group.get("id")); @SuppressWarnings("unchecked") List<VarObject> list=(List<VarObject>) group.get("services"); assertEquals(2, list.size()); //子表的记录也一同查出 System.out.println(list); } { /** * 级联更新 */ VarObject group=db.load(GroupTable.newInstance().set("id", id)); assertEquals(id, group.get("id")); group.set("name", "更新字段"); group.set("serviceId", 123); @SuppressWarnings("unchecked") List<VarObject> list=(List<VarObject>) group.get("services"); list.get(0).set("pname",list.get(0).get("name")); list.get(0).set("name", null); list.get(0).set("flag", false); //修改一个子表的记录 list.remove(1); //删除一个子表的记录 list.add(meta.newInstance().set("name", "service3"));//新增一个子表的记录 /* * 这个操作会对应4个SQL操作,分别用来更新父表、更新子表、删除子表记录、插入子表记录 */ db.updateCascade(group); // //检查数据 group=db.load(GroupTable.newInstance().set("id", id)); assertEquals("更新字段",group.get("name")); assertEquals(123,group.get("serviceId")); int count=0; for(VarObject child: (List<VarObject>)group.get("services")){ count++; if(child.get("name")==null){ assertNotNull(child.get("pname")); } if("service2".equals(child.get("name"))){ throw new IllegalStateException();//这条记录应该已经被删除了,不可能查出来的。 } } assertEquals(2,count); } { /** * 级联删除,这个操作将删除子表中相关的2条记录。然后再删除父表中的记录 */ db.deleteCascade(GroupTable.newInstance().set("id", id)); //检查数据 VarObject group=db.load(GroupTable.newInstance().set("id", id)); assertNull(group); int count=db.count(QB.create(meta)); assertEquals(0,count); } } @IgnoreOn(allButExcept="oracle") @Test public void testX() throws SQLException{ TupleMetadata meta=new TupleMetadata("XXASD"); meta.addColumn("XXX", new ColumnType.Double(17, 12)); db.dropTable(TestEntity.class); db.dropTable(meta); db.createTable(meta); db.createTable(TestEntity.class); } }