package jef.orm.multitable2; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import jef.codegen.EntityEnhancer; import jef.common.log.LogUtil; import jef.database.Condition.Operator; import jef.database.DbClient; import jef.database.PagingIterator; import jef.database.QB; import jef.database.Session; import jef.database.Transaction; import jef.database.query.Query; import jef.database.query.RefField; import jef.database.query.Selects; 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.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 org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; /** * 多表数据库操作 * @author Administrator * */ @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}") }) public class CascadeModel2Test extends org.junit.Assert{ private DbClient db; @DatabaseInit public void prepareData() throws SQLException { db.dropTable(Root.class,Parent.class,Child.class,Leaf.class,EnumationTable.class); db.createTable(Root.class, Parent.class, Child.class, Leaf.class, EnumationTable.class); doInsert(db); } /** * 案例一: 一次性插入四层级联关系的记录 * @throws SQLException */ @Test public void testInsertCascade() throws SQLException{ Transaction db=this.db.startTransaction(); int count1=db.count(QB.create(Root.class)); int count2=db.count(QB.create(Parent.class)); int count3=db.count(QB.create(Child.class)); int count4=db.count(QB.create(Leaf.class)); int rootId=doInsert(db); assertEquals(count1+1, db.count(QB.create(Root.class))); assertEquals(count2+1, db.count(QB.create(Parent.class))); assertEquals(count3+2, db.count(QB.create(Child.class))); assertEquals(count4+4, db.count(QB.create(Leaf.class))); //检测,从数据库读取所有数据 { int n=0; Root root=new Root(rootId); root=db.load(root); n++; System.out.println("staep1"); List<Parent> ps=root.getChildren(); for(Parent p: ps){ n++; System.out.println("staep2"); List<Child> cs=p.getChildren(); for(Child c:cs){ n++; System.out.println("staep3"); List<Leaf> leaf=c.getChildren(); n+=leaf.size(); } } assertEquals(8, n); } db.rollback(true); } /** * 案例二: 一次性删除四层级联关系的记录 * @throws SQLException */ @Test public void testDelete() throws SQLException{ Transaction db=this.db.startTransaction(); int count1=db.count(QB.create(Root.class)); int count2=db.count(QB.create(Parent.class)); int count3=db.count(QB.create(Child.class)); int count4=db.count(QB.create(Leaf.class)); int n=doDelete(db); assertEquals(count1-n, db.count(QB.create(Root.class))); assertEquals(count2-n, db.count(QB.create(Parent.class))); assertEquals(count3-2*n, db.count(QB.create(Child.class))); assertEquals(count4-4*n, db.count(QB.create(Leaf.class))); db.rollback(true); } private int doDelete(Session db) throws SQLException { Query<Root> root=QB.create(Root.class); root.addCondition(QB.eq(Root.Field.code, "test1")); return db.deleteCascade(root.getInstance()); } private int doInsert(Session db) throws SQLException { Root root=new Root(); Parent parent=new Parent(); Child child1=new Child(); Child child2=new Child(); Leaf leaf1=new Leaf(); Leaf leaf2=new Leaf(); Leaf leaf3=new Leaf(); Leaf leaf4=new Leaf(); root.setChildren(Arrays.asList(parent)); parent.setChildren(Arrays.asList(child1,child2)); child1.setChildren(Arrays.asList(leaf1,leaf2)); child2.setChildren(Arrays.asList(leaf3,leaf4)); root.setCode("test1"); child1.setCode("test1"); child2.setCode("test2"); leaf1.setCode("test1"); leaf2.setCode("test1"); leaf3.setCode("test1"); leaf4.setCode("test1"); root.setName("测试Root"); parent.setName("测试parent"); child1.setName("测试child1"); child2.setName("测试child2"); leaf1.setName("测试leaf1"); leaf2.setName("测试leaf2"); leaf3.setName("测试leaf3"); leaf4.setName("测试leaf4"); db.insertCascade(root); return root.getId(); } /** * @案例描述 * Like的用法:四种运算当中,前三种都是Like的进一步封装,框架会执行关键字中的转义,添加通配符等操作。 * 一般在做页面查询等功能时,这三种操作就足够用了。而且没有被SQL注入攻击的可能。 * * 最后一个操作就是数据库原生的like操作。 * * @测试功能 * matchStart运算符 matchEnd运算符 matchAny运算符 like运算符 * @throws SQLException */ @Test public void testLike() throws SQLException { db.select(QB.create(Root.class).addCondition( QB.matchStart(Root.Field.name, "aa_") )); db.select(QB.create(Root.class).addCondition( QB.matchEnd(Root.Field.name, "aa_") )); db.select(QB.create(Root.class).addCondition( QB.matchAny(Root.Field.name, "aa_") )); db.select(QB.create(Root.class).addCondition( QB.like(Root.Field.name, "%aa_") )); //此处为演示like操作的四种用法,观察输出即可 } /** * 在这个案例中,演示添加附加关联关系的例子。 * 四个对象的关系如下所示 * <pre> * Leaf (*--1) Child (*--1) parent (*--1) Root</pre> * 当我们查询Leaf时,默认只查询到Child表,也就是两表关联。而实际上从Leaf到Parent和Root表都是多对一关系。 * 一次查询其实就可以将Leaf和其所属的上级对象全部查出。 * 为此,可以通过以下两种方式之一将Parent表和Root表添加到这次的查询范围中<ol> * <li>使用RefField, FilterCondition等方式添加基于表Root和Parent的排序列或查询条件</li> * <li>调用addExtendQuery方法,提示框架查询时带上指定的表进行查询</li> * </ol> * * @throws SQLException */ @Test public void testTable4Population() throws SQLException { doDelete(db); doInsert(db); //案例二: 查询数据 一次性完成四层级联关系的填充 Query<Leaf> leaf = QB.create(Leaf.class); leaf.addCascadeCondition(QB.matchAny(Child.Field.name, "测试")); leaf.addOrderBy(true, new RefField(Parent.Field.name)); leaf.addExtendQuery(QB.create(Root.class)); PagingIterator<Leaf> leafs = db.pageSelect(leaf, 4); assertEquals(4,leafs.getTotal()); for (Leaf l : leafs.next()) { Child c=l.getParent(); Parent p=c==null?null:c.getParent(); Root t=p==null?null:p.getRoot(); assertNotNull(t); assertEquals("测试Root", t.getName().trim()); //因为root是char(40),数据库会补空格到40字符 assertEquals("测试parent", p.getName()); } } /** * 测试带Ref条件的查询 * @throws SQLException */ @Test public void testSelect() throws SQLException { System.out.println("=========== testSelect Begin =========="); Query<Leaf> q=QB.create(Leaf.class); q.setAllRecordsCondition(); q.addExtendQuery(QB.create(Parent.class)); //通过addExtendQuery告知Parent表也参与联查。 q.addCondition(new RefField(Root.Field.name),Operator.MATCH_ANY,"测试"); q.addOrderBy(false, Leaf.Field.childId); q.addOrderBy(true, new RefField(Root.Field.name)); q.setCascadeViaOuterJoin(true); List<Leaf> ps=db.select(q.getInstance()); assertEquals(4,ps.size()); System.out.println("=========== testSelect End =========="); } /** * 测试级联场景下获取数量 * @throws SQLException */ @Test public void testCount() throws SQLException { System.out.println("=========== testCount Begin =========="); Query<Leaf> q=QB.create(Leaf.class); q.setCascadeViaOuterJoin(true); q.setAllRecordsCondition(); q.addExtendQuery(QB.create(Parent.class));// q.addCondition(new RefField(Root.Field.name),Operator.MATCH_ANY,"123"); System.out.println(db.count(q)); System.out.println("=========== testCount End =========="); // select count(*) // from leaf T1 // left join child T2 ON T1.childId = T2.id // left join enumationtable T3 ON T1.code = T3.code // and T3.type = '4' // left join parent T4 ON T2.parentId = T4.id // left join root T5 ON T4.rootId = T5.ID1 // where T5.THE_NAME like ? escape '/' } @Test @IgnoreOn(allButExcept="hsqldb") public void testCountDistinct() throws SQLException { Query<Leaf> q=QB.create(Leaf.class); q.setCascade(true); Selects items=QB.selectFrom(q); items.column(Leaf.Field.name); items.setDistinct(true); q.getResultTransformer().setResultType(String.class); q.setMaxResult(1); long total=db.count(q);//取总数 LogUtil.show(db.select(q)); //查询,由于总数被限制为1,因此只会查出第一条。 } /** * TODO 当使用了distinct后的自动转换count语句非常复杂,尤其是和分库分表一起使用以后几乎就是一团乱麻。 * 目前支持得不是很好,还需要补充更多案例。 * @throws SQLException */ @Test public void testPageWithDistinct() throws SQLException { Query<Leaf> q=QB.create(Leaf.class); q.setCascade(false); Selects items=QB.selectFrom(q); items.column(Leaf.Field.name); items.setDistinct(true); // db.select(q); q.getResultTransformer().setResultType(String.class); PagingIterator<String> rp=db.pageSelect(q, 3); LogUtil.show(rp.next()); } @Test public void testCount2() throws SQLException { System.out.println("=========== testCount Begin =========="); Query<Leaf> q=QB.create(Leaf.class); q.addExtendQuery(QB.create(Parent.class));// q.setCascadeViaOuterJoin(true); q.addCondition(QB.like(new RefField(Root.Field.code),"t%t_")); int count=db.count(q); assertEquals(4, count); System.out.println("=========== testCount End =========="); } @Test public void testPaging() throws SQLException{ System.out.println("=========== testPaging(Model2) Begin =========="); Query<Leaf> q=QB.create(Leaf.class); PagingIterator<Leaf> page=db.pageSelect(q, 5); System.out.println("Total Page:" + page.getTotalPage()); for(;page.hasNext();){ List<Leaf> list=page.next(); } Query<Leaf> q2=QB.create(Leaf.class); q2.addCondition(Leaf.Field.name,Operator.MATCH_ANY,"a"); page=db.pageSelect(q2, 5); System.out.println("Total Page:" + page.getTotalPage()); for(;page.hasNext();){ List<Leaf> list=page.next(); } Query<Leaf> q3=QB.create(Leaf.class); q3.addCondition(new RefField(Parent.Field.name),Operator.MATCH_ANY,"a"); q3.setCascadeViaOuterJoin(true); page=db.pageSelect(q2, 5); System.out.println("Total Page:" + page.getTotalPage()); for(;page.hasNext();){ List<Leaf> list=page.next(); } System.out.println("=========== testPaging(Model2) End =========="); } /** * @案例描述 测试关联查询 * * Leaf当中有到Child对象的引用,因此查询时会关联这张表 * * * @throws SQLException */ @Test public void testTableCascade1() throws SQLException { Query<Leaf> leaf = QB.create(Leaf.class); List<Leaf> leaves = db.select(leaf); for (Leaf l : leaves) { if (l.getParent() != null) { assertEquals(l.getParentName(), l.getParent().getName()); } else { assertNull(l.getParentName()); } } } /** * 测试关联查询 * * @throws SQLException */ @Test public void testTableCascade2() throws SQLException { Query<Child> q = QB.create(Child.class); q.addCascadeCondition(QB.eq(Leaf.Field.name, "6")); // 关联查询条件 q.setAttribute("aaa", "3"); List<Child> leaves = db.select(q); for (Child l : leaves) { if (l.getParent() != null) { assertEquals(l.getParentId(), Integer.valueOf(l.getParent().getId())); } else { assertNull(l.getParentId()); } if (l.getChildren() != null && l.getChildren().size() > 0) { for (Leaf leaf : l.getChildren()) { assertEquals(leaf.getParent().getId(), l.getId()); } } } } }