package jef.orm.multitable2; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import jef.common.log.LogUtil; import jef.common.wrapper.Holder; import jef.common.wrapper.IntRange; import jef.database.Condition; import jef.database.Condition.Operator; import jef.database.DbClient; import jef.database.DbMetaData.ObjectType; import jef.database.NamedQueryConfig; import jef.database.NativeCall; import jef.database.NativeQuery; import jef.database.ORMConfig; import jef.database.PagingIterator; import jef.database.QB; import jef.database.RecordHolder; import jef.database.RecordsHolder; import jef.database.SqlTemplate; import jef.database.Transaction; import jef.database.VarObject; import jef.database.jdbc.result.IResultSet; import jef.database.jmx.JefFacade; import jef.database.meta.FBIField; import jef.database.meta.Feature; import jef.database.meta.MetaHolder; import jef.database.meta.TupleMetadata; import jef.database.query.Func; import jef.database.query.Join; import jef.database.query.OutParam; import jef.database.query.Query; import jef.database.query.RefField; import jef.database.query.Selects; import jef.database.query.SqlExpression; import jef.database.query.UnionQuery; import jef.database.support.RDBMS; import jef.database.test.DataSource; import jef.database.test.DataSourceContext; import jef.database.test.DatabaseInit; import jef.database.test.IgnoreOn; import jef.database.test.JefJUnit4DatabaseTestRunner; import jef.database.test.LogListener; import jef.database.wrapper.populator.Mapper; import jef.database.wrapper.populator.Mappers; import jef.database.wrapper.populator.Transformer; import jef.orm.multitable.model.Person; import jef.orm.multitable2.model.Child; import jef.orm.multitable2.model.EnumationTable; import jef.orm.multitable2.model.Leaf; import jef.orm.multitable2.model.Parent; import jef.orm.multitable2.model.Root; import jef.orm.multitable2.model.TreeTable; import jef.orm.onetable.model.Foo; import jef.script.javascript.Var; import jef.tools.string.RandomData; import org.apache.commons.lang.math.RandomUtils; import org.apache.commons.lang.time.DateUtils; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; @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 = "hsqldb", url = "jdbc:hsqldb:mem:testhsqldb", user = "sa", password = ""), @DataSource(name = "derby", url = "jdbc:derby:./db;create=true"), @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 NativeQueryTest extends org.junit.Assert { private DbClient db; @BeforeClass public static void enhacne() { ORMConfig.getInstance().setSelectTimeout(20); ORMConfig.getInstance().setUpdateTimeout(20); ORMConfig.getInstance().setDeleteTimeout(20); } @DatabaseInit public void setUp() throws SQLException { try { dropTable(); createtable(); prepareData(); } catch (Exception e) { LogUtil.exception(e); } JefFacade.getOrmConfig().setDebugMode(true); } /** * 准备数据 * * @throws SQLException */ private void prepareData() throws SQLException { { Root[] root = RandomData.newArrayInstance(Root.class, 5); int x = 0; for (Root r : root) { r.setName(String.valueOf(x++)); } db.batchInsert(Arrays.asList(root)); } { Leaf[] leaf = RandomData.newArrayInstance(Leaf.class, 5); for (int i = 0; i < leaf.length; i++) { Leaf e = leaf[i]; e.setChildId(RandomData.randomInteger(1, 5)); } db.batchInsert(Arrays.asList(leaf)); } { EnumationTable[] enums = RandomData.newArrayInstance(EnumationTable.class, 10); for (int i = 0; i < enums.length; i++) { EnumationTable e = enums[i]; e.setCode("code" + i); e.setType("1"); e.setEnable(true); } db.batchInsert(Arrays.asList(enums)); enums = RandomData.newArrayInstance(EnumationTable.class, 10); for (int i = 0; i < enums.length; i++) { EnumationTable e = enums[i]; e.setEnable(true); e.setCode("code" + i); e.setType("2"); } db.batchInsert(Arrays.asList(enums)); } NamedQueryConfig config = new NamedQueryConfig("test_sql_in", "select count(*) from Person_table where id in (:names<int>)", false, 0); if (db.load(config) != null) { db.delete(config); } db.insert(config); Parent[] parent = RandomData.newArrayInstance(Parent.class, 4); for (Parent p : parent) { db.insertCascade(p); } { Child[] children = RandomData.newArrayInstance(Child.class, 4); for (int i = 0; i < children.length; i++) { children[i].setParentId(parent[i].getId());// 给每个Parent对象再加一个child children[i].setCode("code" + i); } db.batchInsert(Arrays.asList(children)); } } private void createtable() throws SQLException { db.createTable(Root.class,Foo.class); db.createTable(Parent.class,Child.class,Leaf.class); db.createTable(EnumationTable.class); db.createTable(TreeTable.class); db.createTable(Person.class); if(db.getProfile().getName()!=RDBMS.oracle && db.getProfile().getName()!=RDBMS.mysql ){ if(!db.existTable("dual")){ db.executeSql("create table dual(X varchar(20))"); } long count=db.getSqlTemplate(null).countBySql("select count(*) from dual"); if(count==0){ db.executeSql("insert into dual values('X')"); } } } private void dropTable() throws SQLException { db.dropTable(Root.class,Parent.class,Child.class,Leaf.class); db.dropTable(EnumationTable.class); db.dropTable(TreeTable.class); } /** * @案例描述 测试自定义的SQL语句的分页查询. 这个案例中,由于使用了distinct关键字,因此count语句也必须使用distinct关键字. * 对于MYSQL,由于不支持 || 字符串拼接,因此其count会以concat(a,b)的方式计算得出 * * @测试功能 框架可以将SQL语句根据当前数据库改写为对应的count语句,从而自动获得分页计数。甚至包括distincat这种特出场景 * @throws SQLException */ @Test public void testNewSQL() throws SQLException { long count = db.getSqlTemplate(null).countBySql("SELECT count(*) FROM PARENT T, Child T1 WHERE T.ID = T1.PARENTID"); System.out.println(count); // /////////////// String sql = "SELECT distinct T.NAME PNAME, T1.NAME FROM parent T, child T1 WHERE T.ID = T1.PARENTID order by t.name"; PagingIterator<Var> pp = db.pageSelect(sql, Var.class, 5); LogListener listener = new LogListener(".+group by T.NAME,T1.NAME.+"); LogUtil.show(pp.hasNext()); LogUtil.show(pp.next()); if (db.getProfile(null).has(Feature.SUPPORT_CONCAT)) { String match = listener.getSingleMatch()[0]; assertNotNull(match); } else { listener.close(); } assertEquals(count, pp.getTotal()); assertEquals(2, pp.getTotalPage()); if(pp.hasNext()){ LogUtil.show(pp.next()); } } /** * 在Criteria API中使用ResultTransformer * @throws SQLException */ @Test public void testCriteriaQueryWithResultTransformer() throws SQLException { Query<Root> t1 = QB.create(Root.class); // t1.addCondition(Root.Field.name,Operator.MATCH_END,"A"); Join join = QB.innerJoin(t1, QB.create(Parent.class), QB.on(Parent.Field.rootId, Root.Field.id)); join.getResultTransformer().setResultType(Object[].class); //当查询结果为Object[]时,只会使用自定义Mapper // 测试1,数组 join.getResultTransformer().addMapper(new Mapper<Object[]>() { @Override protected void transform(Object[] obj, IResultSet rs) throws SQLException { Foo foo = new Foo(); foo.setModified(new Date()); foo.setName("asadsd"); foo.setId(123); obj[0] = foo; } }); List<Object[]> result = db.select(join, null); // 测试2,普通对象 Transformer t = join.getResultTransformer(); t.setResultType(Holder.class); //当查询结果不为Object[],框架会初始化若干缺省的映射器,此时最好清除缺省Mapper再添加自定义Mapper t.clearMapper(); // 清除上一次的自定义映射器 t.ignoreAll(); t.addMapper(new Mapper<Holder<Object>>() { @Override protected void transform(Holder<Object> obj, IResultSet rs) throws SQLException { Foo foo = new Foo(); foo.setModified(new Date()); foo.setName("asadsd"); foo.setId(123); obj.set(foo); } }); List<Holder> result1 = db.select(join, null); System.out.println(result); assertTrue(result.size() > 0); } /** * 在NativeQuery中使用ResultTransformer * @throws SQLException */ @Test public void testNativeQueryWithResultTransformer() throws SQLException { db.createTable(Child.class); { // parent//children//codeObj//codeText List<Child> l1 = db.select(QB.create(Child.class)); System.out.println(l1); } NativeQuery<Child> query = db.createNativeQuery("select c.*,e.text,e.type,e.descrption,e.enable from child c, ENUMATIONTABLE e where c.CODE=e.CODE and e.TYPE='1' ", Child.class); query.getResultTransformer().addMapper(Mappers.toResultProperty("codeObj", EnumationTable.class)); // 自己再添加一个 { query.getResultTransformer().addMapper(new Mapper<Child>() { protected void transform(Child obj, IResultSet rs) throws SQLException { EnumationTable codeObj = new EnumationTable(); codeObj.stopUpdate(); codeObj.setCode(rs.getString("CODE")); codeObj.setType(rs.getString("TYPE")); codeObj.setDesc(rs.getString("DESCRPTION")); codeObj.setName(rs.getString("TEXT")); codeObj.setEnable(rs.getBoolean("ENABLE")); System.out.println("ENABLE=" + rs.getObject("ENABLE") + " obj value=" + codeObj.getEnable()); obj.setCodeObj(codeObj); } }); } List<Child> persons = query.getResultList(); Child first = persons.get(0); assertNotNull(first.getCodeObj().getName()); assertEquals(true, first.getCodeObj().getEnable()); } /** * 在NatiiveQuery中自定义ResultTransformer,返回多个对象(数组)。 * @throws SQLException */ @Test public void testNativeQueryReturnMulitpleObjects() throws SQLException { NativeQuery<Object[]> query = db.createNativeQuery("select c.*,e.* from child c, ENUMATIONTABLE e where c.CODE=e.CODE and e.TYPE='1' ", Object[].class); query.getResultTransformer().addMapper(Mappers.toArrayElement(2, Child.class)); query.getResultTransformer().addMapper(Mappers.toArrayElement(1, EnumationTable.class)); List<Object[]> persons = query.getResultList(); assertNotNull(persons.get(0)[1]); assertNotNull(persons.get(0)[2]); } /** * 这个案例测试直接将简单的列拼为数组进行返回。 如果所有的值可以确定都为String,可以用String[]作为返回格式 * * @throws SQLException */ @Test @IgnoreOn(allButExcept = "derby") public void testSlelectSimpleValueArray() throws SQLException { NativeQuery<Object[]> objs = db.createNativeQuery("select 'Asa' as a ,'B' as b,1+1 as c, current_timestamp as D from dual", Object[].class); Object[] result = objs.getSingleResult(); assertTrue(result[1].getClass() == String.class); assertTrue(result[2].getClass() == Integer.class); assertTrue(result[3].getClass() == Timestamp.class); } /** * @错误用法案例 * * 这个案例中,输入的表达式实际上是有多个表达式拼合而成的SQL片段,不符合表达式的定义,因此无法查询。 * * @throws SQLException */ @Test(expected = Exception.class) @IgnoreOn(allButExcept = "derby") public void testSelectExpressionOfError() throws SQLException { Object[] result = db.getExpressionValue("'Asa' as a ,'B' as b,1+1 as c, current_timestamp", Object[].class); System.out.println(result); } /** * * 分类: Criteria API * @案例描述 TreeTable中包含了一个对leaf表的引用。因此虽然查询时我们看似只查一张表,查询时会自动关联两张表。 * 同时我们可以使用RefField (Reference * Field)这个对象将关联表(B)的查询条件,甚至排序条件也传入表(A)的条件中。 * * @测试功能 使用RefField在ManyToOne或OneToOne时,设置关联表的查询条件和排序字段。 * @throws SQLException */ @Test public void testRefFieldRefWhererAndOrder() throws SQLException { Query<TreeTable> q = QB.create(TreeTable.class); q.addCondition(TreeTable.Field.name, "a"); q.addCondition(new RefField(Leaf.Field.childId), 12); q.addOrderBy(true, new RefField(Leaf.Field.id)); LogListener listener = new LogListener("select .* where (.+) order by (.+) \\|.+", Pattern.DOTALL); db.select(q); String[] match = listener.getSingleMatch(); assertEquals("t1.name=? and t2.childid=?", match[0].toLowerCase().trim()); assertEquals("t2.id asc", match[1].toLowerCase().trim()); } /** * 分类: Criteria API * @案例描述 复杂条件下的关联查询和自定义Join混合使用 * * @测试功能 1. 在Query中添加两个相同的条件,实际使用时会自动合并成一个。 2. QB.or QB.eq QB.ge等条件生成的用法 * 3.xxxJoinWithRef可以将Join左边的对象自身的静态关联关系保留的情况下和新的表进行join * * @throws SQLException */ @Test public void testCascadeAndJoin() throws SQLException { Child c = new Child(); c.setName("a"); c.setCode("code1"); c.setParentId(10); db.insert(c); Parent parent = new Parent(); parent.setName("parent"); parent.setId(10); db.insert(parent); Query<Child> query = QB.create(Child.class); query.addCondition(QB.or(Condition.get(Child.Field.name, Operator.EQUALS, "a"), QB.ge(Child.Field.parentId, 5))); query.addCondition(QB.or(QB.eq(Child.Field.name, "a"), QB.ge(Child.Field.parentId, 5))); query.setAttribute("aaa", "3"); // db.select(query); Query<EnumationTable> t3 = QB.create(EnumationTable.class); Join j = QB.leftJoinWithRef(query, t3, QB.on(Child.Field.name, EnumationTable.Field.code), QB.on(EnumationTable.Field.type, "2")); Selects select = QB.selectFrom(j); select.noColums(t3); j.setAttribute("aaa", "3"); j.getResultTransformer().setResultType(Child.class); List<Child> list = db.select(j, null); LogUtil.show(list); assertEquals(db.loadBySql("select count(*) from child where name='a' or parentId>=5", Integer.class).intValue(), list.size()); } /** * 分类Criteria API * * 带排序的自动分页查询 * @throws SQLException */ @Test public void testPageIngIn() throws SQLException { Query<Root> t1 = QB.create(Root.class); t1.addCondition(Root.Field.name, "123"); t1.addCondition(QB.between(Root.Field.range, 1, 4)); t1.addOrderBy(true, Root.Field.id); PagingIterator<Root> p = db.pageSelect(t1, 4); p.setOffset(3); p.getTotal(); } @Test public void testAllColumns() throws SQLException { Query<Root> t1 = QB.create(Root.class); Query<Parent> t2 = QB.create(Parent.class); for (int i = 0; i < 10; i++) { Root iroot = RandomData.newInstance(Root.class); db.insert(iroot); } for (int i = 0; i < 10; i++) { Parent iparent = RandomData.newInstance(Parent.class); db.insert(iparent); } Join join = QB.innerJoin(t1, t2, QB.on(Root.Field.id, Parent.Field.id)); Selects select = QB.selectFrom(join); select.allColumns(t1); select.noColums(t2); join.getResultTransformer().setResultType(Root.class); List<Root> root = db.select(join, null); System.out.println(root); } /** * 一个充分定制化的查询 实际产生的SQL和testSQL是一样的,然后拼装到一个自定义的对象中去 * * @throws SQLException */ @Test public void testSelectJoin() throws SQLException { Query<Root> t1 = QB.create(Root.class); t1.addCondition(Root.Field.range, 1); t1.addCondition(Root.Field.name, "ads"); Query<Leaf> t2 = QB.create(Leaf.class); t2.addCondition(Leaf.Field.name, "sasd"); Join join = QB.innerJoin(t1, t2, QB.on(Root.Field.id, Leaf.Field.childId)); t1.setOrderBy(true, Root.Field.id); // Query<EnumTable> t3 = join.leftJoin(QB.create(EnumTable.class), // QB.on(Root.Field.id, EnumTable.Field.id), QB.on(EnumTable.Field.type, // ">1")); // Query<EnumTable> t4 = join.leftJoin(QB.create(EnumTable.class), // QB.on(Leaf.Field.id, EnumTable.Field.id), QB.on(EnumTable.Field.type, // "2")); Selects select = QB.selectFrom(join); select.columns(t1, "name as rootName,id as rootId"); select.columns(t2, "id as id,name as name"); // select.column(t3, "desc").as("enumOfRoot"); // select.column(t4, "desc").as("enumOfLeaf"); join.addOrderBy(true, new RefField(Root.Field.range)); join.getResultTransformer().setResultType(ResultContainer.class); List<ResultContainer> map = db.select(join, new IntRange(1, 1)); System.out.println("===========result=============="); // LogUtil.show(map.get(0)); System.out.println("asaaaaaaaaaaaaaaaaaaaaa==========================="); } /** * 使用SQL来完成上面的复杂查询(testSelectJoin),效果是一样的 * * * PG在列的别名之前是一定要加上as的 * * @throws SQLException */ @IgnoreOn({ "postgresql" }) @Test public void testSQL() throws SQLException { String sql = "select T1.THE_NAME rootName,t1.code code, T1.ID1 rootId,T2.ID id, T2.NAME name, T3.descrption enumOfRoot," + "T4.descrption enumOfLeaf from ROOT T1 INNER JOIN LEAF T2 ON T1.ID1 = T2.CHILDID LEFT JOIN ENUMATIONTABLE T3 ON T1.Code = T3.code and T3.TYPE = '1' LEFT JOIN ENUMATIONTABLE T4 ON T2.Code = T4.code and T4.TYPE = '2'"; List<ResultContainer> result = db.selectBySql(sql, new Transformer(ResultContainer.class), new IntRange(1, 10)); System.out.println("===========result=============="); if (result.size() > 0) LogUtil.show(result.get(0)); } @IgnoreOn({ "postgresql" }) @Test public void testLoadBySQL() throws SQLException { { String sql = "select T1.THE_NAME rootName,t1.code code, T1.ID1 rootId,T2.ID id, T2.NAME name, T3.descrption enumOfRoot," + "T4.descrption enumOfLeaf from ROOT T1 INNER JOIN LEAF T2 ON T1.ID1 = T2.CHILDID LEFT JOIN ENUMATIONTABLE T3 ON T1.Code = T3.code and T3.TYPE = '1' LEFT JOIN ENUMATIONTABLE T4 ON T2.Code = T4.code and T4.TYPE = '2' where id=?"; ResultContainer result = db.loadBySql(sql, ResultContainer.class, 2); System.out.println("===========result=============="); // Assert.assertNotNull(result); LogUtil.show(result); Var v = db.loadBySql(sql, Var.class, 2); LogUtil.show(v); } } @IgnoreOn(allButExcept = { "oracle" }) @Test public void testLoadBySQLWithSimpleValue() throws SQLException { { String sql = "select 'AA' from dual"; String result = db.loadBySql(sql, String.class); System.out.println("===========result=============="); assertEquals("AA", result); LogUtil.show(result); Var v = db.loadBySql(sql, Var.class); LogUtil.show(v); } { String sql = "select 123 from dual"; int result = db.loadBySql(sql, Integer.class); System.out.println("===========result=============="); assertEquals(123, result); LogUtil.show(result); } { String sql = "select sysdate from dual"; Date result = db.loadBySql(sql, Date.class); System.out.println("===========result=============="); System.out.println(result.getClass()); LogUtil.show(result); assertTrue(DateUtils.isSameDay(new Date(), result)); } } @Test @IgnoreOn(allButExcept="sqlite") public void testLoadSimpleValue() throws SQLException { SqlTemplate sqlTemplate = db.getSqlTemplate(null); { String result = sqlTemplate.getExpressionValue("'AA'", String.class); System.out.println("===========result=============="); assertEquals("AA", result); LogUtil.show(result); } { int result = sqlTemplate.getExpressionValue("123", Integer.class); System.out.println("===========result=============="); assertEquals(123, result); LogUtil.show(result); } { Date result = sqlTemplate.getExpressionValue(Func.current_date, Date.class); System.out.println("===========result=============="); LogUtil.show(result); System.out.println(new Date()); assertTrue(DateUtils.isSameDay(new Date(), result)); } } /** * 这个案例演示NativeQuery支持重复使用。 * * @throws SQLException */ @Test @IgnoreOn("derby") public void testNativeQueryWithSimpleValue() throws SQLException { { /** * 测试NativeQuery是否可在查询中绑定多组不同的参数 */ String sql = "select :val from ROOT"; NativeQuery<String> nq = db.createNativeQuery(sql, String.class); nq.setParameter("val", "1234aaa"); String a = nq.getSingleResult(); assertEquals("1234aaa", a); nq.setParameter("val", "545454aaa"); a = nq.getSingleResult(); assertEquals("545454aaa", a); } { Transaction session = db.startTransaction(); /** * 测试是否可以在写语句中绑定多组不同的参数 */ String sql = "delete from ROOT where THE_NAME=:val"; NativeQuery<String> nq = session.createNativeQuery(sql, String.class); nq.setParameter("val", "1234aaa"); int a = nq.executeUpdate(); System.out.println(a); nq.setParameter("val", "545454aaa"); a = nq.executeUpdate(); System.out.println(a); session.close(); } System.out.println("=============================================="); { Transaction session = db.startTransaction(); try{ /** * 当绑定多组不同的表达式时,是否可以正确处理二元表达式自动省略 */ String sql = "delete from ROOT where 1=1 and (THE_NAME=:val or THE_NAME =:val2)"; NativeQuery<String> nq = session.createNativeQuery(sql, String.class); nq.setParameter("val", "545454bbbb"); int a = nq.executeUpdate(); System.out.println(a); nq.setParameter("val", "545454aaa"); nq.setParameter("val2", "vvv2"); a = nq.executeUpdate(); System.out.println(a); // 清除之前设置过的参数。 nq.clearParameters(); a = nq.executeUpdate(); System.out.println(a); }finally{ session.close(); } } } /** * 两个单表union查询 * * @throws SQLException */ @SuppressWarnings("unchecked") @Test @IgnoreOn(allButExcept="derby") public void testSelectUnion() throws SQLException { Query<Leaf> q1 = QB.create(Leaf.class); q1.addCondition(Leaf.Field.id, 1); Query<Leaf> q2 = QB.create(Leaf.class); q2.addCondition(Leaf.Field.id, 3); q2.orderByAsc(Leaf.Field.code); UnionQuery<Leaf> union = QB.union(q1, q2); union.setOrderBy(false, Leaf.Field.name); // union.addOrderBy(false, new FBIField("alias_name")); int start = 1; int limit = 5; PagingIterator<Map> leafp = db.pageSelect(union, Map.class, limit); leafp.setOffset(start); LogUtil.show(leafp.getTotal()); LogUtil.show(leafp.next()); } @SuppressWarnings("unchecked") @Test public void testSelectUnionAll() throws SQLException { Query<Leaf> q1 = QB.create(Leaf.class); q1.addCondition(Leaf.Field.id, 1); Query<Leaf> q2 = QB.create(Leaf.class); q2.addCondition(Leaf.Field.id, 3); UnionQuery<Leaf> union = QB.unionAll(q1, q2); union.setOrderBy(false, Leaf.Field.name); // union.addOrderBy(false, new FBIField("alias_name")); union.getResultTransformer().setResultType(Map.class); union.orderByAsc(Leaf.Field.code); int start = 1; int limit = 5; PagingIterator<Map> leafp = db.pageSelect(union, limit); leafp.setOffset(start); LogUtil.show(leafp.getTotal()); LogUtil.show(leafp.next()); } @Test public void testSQLExpression() throws SQLException { Query<Root> query = QB.create(Root.class); query.addCondition(Root.Field.range, 12); query.addCondition(new SqlExpression("THE_NAME='123'")); // query.getResultTransformer().setResultType(Map.class); List<Map> maps = db.selectAs(query, Map.class); LogUtil.show(maps); assertTrue(maps.isEmpty()); } /** * @分类 Criteria高级用法 * * 两个完全不同的表,一个连接查询,一个单表查询,用unionAll合并。 并且拼装到自定义的数据结构中去 * * @throws SQLException */ @Test @IgnoreOn({ "gbase" }) public void testSelectJoinUnion() throws SQLException { // 查询1: Query<Root> t1 = QB.create(Root.class); Query<Leaf> t2 = QB.create(Leaf.class); Join join = QB.innerJoin(t1, t2, QB.on(Root.Field.id, Leaf.Field.childId)); Query<EnumationTable> t3 = QB.create(EnumationTable.class); Query<EnumationTable> t4 = QB.create(EnumationTable.class); join.leftJoin(t3, QB.on(Root.Field.code, EnumationTable.Field.code), QB.on(EnumationTable.Field.type, "1")); join.leftJoin(t4, QB.on(Leaf.Field.code, EnumationTable.Field.code), QB.on(EnumationTable.Field.type, "2")); Selects select = QB.selectFrom(join); select.column(new FBIField("upper(name)", t1)).as("rootName"); // column // 方法中允许写select的表达式 select.columns(t2, "id as id"); // columns中允许写多个字段和字段的别名 select.column(t3, EnumationTable.Field.desc).as("enumOfRoot"); select.column(t4, EnumationTable.Field.desc).as("enumOfLeaf"); // 同一张表Join两次,因此需要通过指定查询实例才能确定选择那张表上的列 // 查询2: Query<Person> union2 = QB.create(Person.class); QB.selectFrom(union2).column(union2, "name").as("rootName"); QB.selectFrom(union2).columns(union2, "id ,cell as enumOfRoot,phone as enumOfLeaf"); // 结果合并 UnionQuery<ResultContainer> union = QB.unionAll(ResultContainer.class, join, union2); union.addOrderBy(true, new FBIField("enumOfLeaf")); // 指定union后的排序列 List<ResultContainer> map = db.select(union, new IntRange(2, 10)); // 限定结果 LogUtil.show(map.get(0)); } /** * 测试命名查询 * * @throws SQLException */ @Test public void testNamedQuery() throws SQLException { NativeQuery<Integer> query = db.createNamedQuery("testIn", Integer.class); query.setParameter("names", new int[] { 1, 2, 3 }); int i = query.getSingleResult(); System.out.println(i); } /** * 测试命名查询的自动省略功能(不输入的条件对应的二元表达式将省略) * * @throws SQLException */ @Test public void testNamedQueryComplex() throws SQLException { NativeQuery<TextValuePair> query = db.createNamedQuery("testComplex", TextValuePair.class); query.setParameter("column", new SqlExpression("code as value, the_name as text")); query.setParameter("id", new int[] { 1, 2, 3 }); query.setParameter("code", 2); query.setParameter("name", "sa"); try { query.setParameter("orderBy", new SqlExpression("id1")); } catch (Exception ex) { LogUtil.exception(ex); } List<TextValuePair> result = query.getResultList(); System.out.println(result); } /** * 测试命名查询 * * @throws SQLException */ @Test public void testNamedQueryComplex2() throws SQLException { NativeQuery query = db.createNamedQuery("testComplex2"); Map<String, Object> map = new HashMap<String, Object>(); map.put("id", new int[] { 1, 2 }); map.put("code", "1"); map.put("column", "id1, the_name, code"); map.put("orderBy", "id1"); query.setParameterMap(map); List<Map> result = query.getResultList(); System.out.println("ok"); } @Test public void testNativeQuery() throws SQLException { String sql = "select * from root where id1=?1 and code=?2"; NativeQuery<Root> query; query = db.createNativeQuery(sql, Root.class); query.setParameter(2, "123"); query.setParameter(1, 12); query.getResultList(); } @Test public void testNamedQueryConfigedInDb() throws SQLException { NativeQuery<Integer> query = db.createNamedQuery("test_sql_in", Integer.class); query.setParameter("names", new int[] { 1, 2, 3 }); int i = query.getSingleResult(); System.out.println(i); } /** * 测试命名查询 * * @throws SQLException */ @Test @IgnoreOn("sqlserver") public void testNamedQueryPaging() throws SQLException { NativeQuery<Root> query = db.createNamedQuery("testPage", Root.class); query.setFirstResult(3); PagingIterator<Root> m = db.pageSelect(query, 3); while (m.hasNext()) { LogUtil.show(m.next()); } } /** * 测试带表达式的更新语句 * * @throws SQLException */ @Test public void functionalUpdate() throws SQLException { Leaf leaf = new Leaf(); leaf.setId(1); leaf.prepareUpdate(Leaf.Field.childId, new SqlExpression("childId+:aa")); leaf.getQuery().setAttribute("aa", 100); db.update(leaf); } /** * 直接修改结果集 案例一、load出多一条记录,并进行修改/删除 * * @throws SQLException */ @Test @IgnoreOn({"sqlite","sqlserver"}) public void testLoadForUpdate() throws SQLException { RecordHolder<Root> holder = db.loadForUpdate(new Root(1)); // if (holder != null) { holder.get().setName("更新值"); holder.get().setRange(2); holder.commit(); holder.close(); } Transaction trans=db.startTransaction(); RecordHolder<Root> holder2 = trans.loadForUpdate(new Root(1)); if (holder2 != null) { LogUtil.show(holder.get()); holder2.delete();// 删除 holder.close(); //此处的Holder写错了。应该为holder2,关闭holder造成锁表泄漏。 } trans.close(); //好在上面的ResultSet是在事务里的,此处事务关闭,顺便将之前泄漏的结果集给关闭了 //结论——悲观锁使用非常危险,一个小小的笔误就会引起严重的泄漏事故。 System.out.println("================="); } /** * 关于Oracle使用char类型时,绑定变量如不padding空格,则无法查出的问题 * * @throws SQLException */ @Test public void lastTest() throws SQLException { Root root = new Root(10); root.setName("123"); db.insert(root); Query<Root> q = QB.create(Root.class); q.addCondition(Root.Field.name, "123 "); db.select(q, null); } /** * @ * 直接修改结果集案例二、 elect出多条记录,并进行修改/删除/插入 的测试案例 * * @throws SQLException */ @Test @IgnoreOn({"sqlite","sqlserver"}) public void testSelectForUpdate() throws SQLException { RecordsHolder<Root> holder = db.selectForUpdate(QB.create(Root.class).getInstance()); int size; try{ int n = 0; for (Root r : holder.get()) { n++; r.setName("更新第" + n + "条。"); // 修改对象中的值 } size = holder.size(); assertTrue(size > 0); System.out.println("count:" + n); Root rootOld = holder.get().get(holder.size() - 1); System.out.println("To DELTET " + rootOld.getId()); holder.delete(holder.size() - 1); // 删除结果集中的最后一条记录。 size--; if (holder.supportsNewRecord()) { Root root = holder.newRecord(); // 创建一条新纪录 root.setName("新插入的记录"); size++; } holder.commit(); // 提交上述修改(更新、删除、添加) }finally{ holder.close(); } List<Root> newResult = db.select(QB.create(Root.class)); assertEquals(size, newResult.size()); } /** * 一个充分定制化的查询 实际产生的SQL和testSQL是一样的,然后拼装到一个自定义的对象中去 * * @throws SQLException */ @Test public void testSelectMultiObject() throws SQLException { System.out.println("===========testSelectObjectMap=============="); Query<Root> t1 = QB.create(Root.class); Query<Leaf> t2 = QB.create(Leaf.class); Join join = QB.innerJoin(t1, t2, QB.on(Root.Field.id, Leaf.Field.childId)); Query<EnumationTable> t3 = QB.create(EnumationTable.class); Query<EnumationTable> t4 = QB.create(EnumationTable.class); join.leftJoin(t3, QB.on(Root.Field.code, EnumationTable.Field.code), QB.on(EnumationTable.Field.type, "1")); join.leftJoin(t4, QB.on(Leaf.Field.code, EnumationTable.Field.code), QB.on(EnumationTable.Field.type, "2")); List<Object[]> map = db.selectAs(join, Object[].class, new IntRange(1, 10)); if (!map.isEmpty()) { Object[] dm = map.get(0); } } /** * 测试使用了Oreacle专用语句的命名查询。 * 命名查询支持方言,因此可以在写了方言SQL的数据库上使用 * * @throws SQLException */ @Test @IgnoreOn(allButExcept="sqlserver") public void testStartWith() throws Exception { try { // db.dropTable("sys_resource"); if (!db.existTable("sys_resource")) { db.createNamedQuery("testOracleTree_create").executeUpdate(); TupleMetadata tuple=MetaHolder.initMetadata(db, "sys_resource"); VarObject map=tuple.newInstance(); map.set("id", 1); map.set("parentId", 0); map.set("name", "Root"); db.insert(map); map=tuple.newInstance(); map.set("id", 2); map.set("parentId", 1); map.set("name", "A22"); db.insert(map); map=tuple.newInstance(); map.set("id", 4); map.set("parentId", 2); map.set("name", "A444"); db.insert(map); map=tuple.newInstance(); map.set("id", 5); map.set("parentId", 1); map.set("name", "A555"); db.insert(map); map=tuple.newInstance(); map.set("id", 6); map.set("parentId", 2); map.set("name", "A33"); db.insert(map); } ORMConfig.getInstance().setAllowRemoveStartWith(true); NativeQuery<Map> q = db.createNamedQuery("testOracleTree", Map.class); q.setParameter("value",2); for(Map ss:q.getResultList()){ System.out.println(ss); } } catch (Exception e) { e.printStackTrace(); throw e; } } /** * 在查询中使用一个自行编写的子查询表达式。 * * @throws SQLException */ @Test public void testSelectExpression() throws SQLException { Query<Root> query = QB.create(Root.class); Selects select = QB.selectFrom(query); select.sqlExpression("(select name as childname from child c where c.id=$1.id1)").as("sss"); LogUtil.show(db.selectAs(query, Map.class)); } /** * @案例说明 测试存储过程 * * @throws SQLException */ @Test @IgnoreOn(allButExcept = { "oracle", "mysql" }) public void testProcessdure() throws SQLException { boolean flag = db.getMetaData(null).exists(ObjectType.PROCEDURE, "INSERT_USER"); if (!flag) { throw new IllegalArgumentException("请先创建存储过程再运行此案例。" + db.getProfile().getName()); } // 案例1 { NativeCall call1 = db.createNativeCall("INSERT_USER", String.class, Integer.class); call1.setParameters("张三你", RandomData.randomInteger(1, 1000000)); call1.execute(); } System.out.println("存储过程insert_user执行后"); // List<D> result=db.selectAll(D.class); // LogUtil.show(result); System.out.println("========================="); // 案例2 { NativeCall call2 = db.createNativeCall("Check_user", String.class, OutParam.typeOf(Integer.class)); call2.setParameters("张三你"); call2.execute(); Object obj = call2.getOutParameter(2); LogUtil.show(obj); } flag = flag && db.getMetaData(null).exists(ObjectType.PROCEDURE, "GET_ALL_USER"); if (flag) { // Oracle // 案例3 { NativeCall call3 = db.createNativeCall("GET_ALL_USER", OutParam.listOf(Map.class)); call3.execute(); List<Map> obj = call3.getOutParameterAsList(1, Map.class); call3.close(); org.junit.Assert.assertTrue(obj.size() > 0); // LogUtil.show(obj); } // 案例4 { String sql = "declare " + " l_line varchar2(255); " + " l_done number; " + " l_buffer long; " + "begin " + " loop " + " exit when length(l_buffer)+255 > :maxbytes OR l_done = 1; " + " dbms_output.get_line( l_line, l_done ); " + " l_buffer := l_buffer || l_line || chr(10); " + " end loop; " + " :done := l_done; " + " :buffer := l_buffer; " + "end;"; NativeCall call3 = db.createAnonymousNativeCall(sql, Integer.class, OutParam.typeOf(Integer.class), OutParam.typeOf(String.class)); call3.execute(26000); System.out.println(call3.getOutParameter(2) + " || " + call3.getOutParameter(3)); } } else { if (db.getProfile().getName() == RDBMS.oracle) { throw new IllegalArgumentException(); } } } /** * 这个案例中使用了Oracle的rowid * * @throws SQLException */ @Test @IgnoreOn({ "gbase", "mysql", "derby", "postgresql", "hsqldb" ,"sqlserver"}) public void testExecuteSqlBatch() throws SQLException { List<String> rowids = db.selectBySql("select t.rowid from leaf t", String.class); List<?>[] rowArray = new List<?>[rowids.size()]; List<Object> list = null; int i = 0; for (String rowid : rowids) { list = new ArrayList<Object>(); list.add(rowid); list.add(RandomUtils.nextInt(9999999)); rowArray[i++] = list; } int count = db.count(QB.create(Leaf.class)); db.getSqlTemplate(null).executeSqlBatch("delete from leaf where rowid = ? and id = ?", rowArray); // 由于删除条件id的值均匹配不上,所以executeSqlBatch执行后,表中数据量应无变化 org.junit.Assert.assertEquals(count, db.select(QB.create(Leaf.class)).size()); } public static class ResultContainer { private int id; private int rootId; private String name; private String rootName; private String enumOfLeaf; private String enumOfRoot; private String code; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getRootId() { return rootId; } public void setRootId(int rootId) { this.rootId = rootId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRootName() { return rootName; } public void setRootName(String rootName) { this.rootName = rootName; } public String getEnumOfLeaf() { return enumOfLeaf; } public void setEnumOfLeaf(String enumOfLeaf) { this.enumOfLeaf = enumOfLeaf; } public String getEnumOfRoot() { return enumOfRoot; } public void setEnumOfRoot(String enumOfRoot) { this.enumOfRoot = enumOfRoot; } } }