package org.easyframe.tutorial.lesson8; import java.sql.SQLException; import java.sql.Timestamp; import java.util.Arrays; import java.util.Date; import java.util.List; import javax.persistence.Column; import org.apache.commons.lang.builder.ToStringBuilder; import org.easyframe.tutorial.lesson2.entity.Student; import org.easyframe.tutorial.lesson4.entity.DataDict; import org.easyframe.tutorial.lesson4.entity.Person; import org.easyframe.tutorial.lesson4.entity.School; import org.easyframe.tutorial.lesson5.entity.Item; import org.junit.BeforeClass; import org.junit.Test; import jef.common.Entry; import jef.common.wrapper.Holder; import jef.database.DbClient; import jef.database.DbClientBuilder; import jef.database.NativeQuery; import jef.database.ORMConfig; import jef.database.QB; import jef.database.Session.PopulateStrategy; import jef.database.jdbc.result.IResultSet; import jef.database.query.Join; import jef.database.query.Query; import jef.database.query.Selects; import jef.database.wrapper.populator.Mapper; import jef.database.wrapper.populator.Mappers; import jef.database.wrapper.populator.Transformer; import jef.tools.DateUtils; /** * 演示 指定查询结果的装配方法,从而让数据库查询结果转换为需要的类型。 * @author jiyi * */ public class Case1 extends org.junit.Assert { private static DbClient db; /** * 测试数据准备 * * @throws SQLException */ @BeforeClass public static void setup() throws SQLException { db = new DbClientBuilder().setEnhancePackages("org.easyframe.tutorial").build(); ORMConfig.getInstance().setDebugMode(false); db.dropTable(Person.class, Item.class, Student.class, School.class, DataDict.class); db.createTable(Person.class, Item.class, Student.class, School.class, DataDict.class); DataDict dict1 = new DataDict("USER.GENDER", "M", "男人"); DataDict dict2 = new DataDict("USER.GENDER", "F", "女人"); db.batchInsert(Arrays.asList(dict1, dict2)); Person p = new Person(); p.setGender('M'); p.setName("张飞"); p.setCurrentSchool(new School("成都大学")); db.insertCascade(p); p = new Person(); p.setGender('M'); p.setName("关羽"); p.setCurrentSchool(new School("襄阳大学")); db.insertCascade(p); p = new Person(); p.setGender('M'); p.setName("刘备"); p.setCurrentSchoolId(1); db.insert(p); Item item = new Item(); item.setName("张飞"); item.setCatalogyId(12); db.insert(item); Student st = new Student(); st.setName("张飞"); st.setDateOfBirth(DateUtils.getDate(1984, 7, 1)); st.setGender("F"); st.setGrade("3"); db.insert(st); st = new Student(); st.setName("关羽"); st.setDateOfBirth(DateUtils.getDate(1980, 2, 1)); st.setGender("F"); st.setGrade("2"); db.insert(st); ORMConfig.getInstance().setDebugMode(true); } /** * 演示特性:8.1.1 返回简单对象 返回简单类型的结果 * * @throws SQLException */ @Test public void testResultType_returnSimpleType() throws SQLException { // 返回String Query<Person> query = QB.create(Person.class); Selects select = QB.selectFrom(query); select.column(Person.Field.gender); List<String> result = db.selectAs(query, String.class); System.out.println(result); // 返回data NativeQuery<Date> nq = db.createNativeQuery("select created from t_person", Date.class); List<Date> results = nq.getResultList(); System.out.println(results); // 返回数字 List<Integer> result2 = db.selectBySql("select count(*) from t_person group by gender", Integer.class); System.out.println(result2); } /** * 演示特性 8.1.2 返回和查询表匹配的对象 * * @throws SQLException */ @Test public void testResultType_returnTableObject() throws SQLException { List<Person> persons = db.select(QB.create(Person.class)); assertEquals(3, persons.size()); } /** * 演示特性 8.1.3 返回任意容器对象 * * @throws SQLException */ @Test public void testResultType_otherDataObject1() throws SQLException { // 普通查询,查询结果改用自定义的类PersonResult来包装. Query<Person> q1 = QB.create(Person.class); List<PersonResult> result = db.selectAs(q1, PersonResult.class); PersonResult first = result.get(0); // Person表中查出的current_school_id字段无用处,被丢弃。 // PersonResult中的字段birthday不存在,不赋值 System.out.println(ToStringBuilder.reflectionToString(first)); // 用NativeQuery来查询Person表,查询结果包装为PersonResult String sql = "select t.*,sysdate as birthday from t_person t"; NativeQuery<PersonResult> q = db.createNativeQuery(sql, PersonResult.class); PersonResult p = q.getSingleResult(); System.out.println(ToStringBuilder.reflectionToString(p)); } public static class PersonResult { @Column(name = "person_name") private String personName; private String id; private String gender; private Date birthday; private int age; public String getPersonName() { return personName; } public void setPersonName(String personName) { this.personName = personName; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } /** * 演示特性 8.1.3 返回任意容器对象 * * @throws SQLException */ @Test public void testResultType_otherDataObject2() throws SQLException { // 用Person表查出Student对象。 { Query<Person> query = QB.create(Person.class); Selects select = QB.selectFrom(query); select.columns("id, name as name, gender, '3' as grade, created as dateOfBirth"); List<Student> result = db.selectAs(query, Student.class); Student first = result.get(0); assertNotNull(first.getGender()); assertNotNull(first.getGrade()); assertNotNull(first.getName()); assertNotNull(first.getDateOfBirth()); assertNotNull(first.getId()); } // 用Person表查出Student对象。(这种写法虽然啰嗦,但是可以利用java编译器检查字段的正确性) { Query<Person> query = QB.create(Person.class); Selects select = QB.selectFrom(query); select.column(Person.Field.id); select.column(Person.Field.name).as("name"); select.column(Person.Field.gender); select.sqlExpression("'3'").as("grade"); select.column(Person.Field.created).as("dateOfBirth"); List<Student> result = db.selectAs(query, Student.class); System.out.println(result); Student first = result.get(0); assertNotNull(first.getGender()); assertNotNull(first.getGrade()); assertNotNull(first.getName()); assertNotNull(first.getDateOfBirth()); assertNotNull(first.getId()); } // 用NativeSQL做到上一点 { String sql = "select id,person_name as name, gender, '3' as grade, created as date_of_birth from t_person"; NativeQuery<Student> nq = db.createNativeQuery(sql, Student.class); List<Student> result = nq.getResultList(); Student first = result.get(0); assertNotNull(first.getGender()); assertNotNull(first.getGrade()); assertNotNull(first.getName()); assertNotNull(first.getDateOfBirth()); assertNotNull(first.getId()); System.out.println(result); } } /** * 演示特性 8.1.3 返回任意容器对象 * * @throws SQLException */ @Test public void testResultType_otherDataObject3() throws SQLException { String sql = "select gender as \"key\",count(*) as value from t_person group by gender"; List<Entry> results = db.selectBySql(sql, jef.common.Entry.class); System.out.println(results); } /** * 特性演示 8.1.6 多个列以数组形式返回 * * @throws SQLException */ @Test public void testSlelectSimpleValueArray() throws SQLException { NativeQuery<Object[]> query = db.createNativeQuery("select 'Asa' as a ,'B' as b,1+1 as c, current_timestamp as D from student", Object[].class); Object[] result = query.getSingleResult(); assertTrue(result[1].getClass() == String.class); assertTrue(Number.class.isAssignableFrom(result[2].getClass())); assertTrue(result[3].getClass() == Timestamp.class); } /** * 特性演示 8.1.6 多个列以数组形式返回 用数组返回结果。每个元素代表一列的值 * * @throws SQLException */ @Test public void testResultType_columnAsArray() throws SQLException { String sql = "select t1.id,person_name,gender,t2.name from t_person t1," + "school t2 where t1.current_school_id=t2.id"; { NativeQuery<String[]> q1 = db.createNativeQuery(sql, String[].class); // 每个列的值被转换为String,每行记录变为一个String[]。 for (String[] array : q1.getResultList()) { System.out.println(Arrays.toString(array)); } } { NativeQuery<Object[]> q2 = db.createNativeQuery(sql, Object[].class); for (Object[] array : q2.getResultList()) { // 每个列的值被保留了其原始类型,每行记录变为一个Object[]。 System.out.println(Arrays.toString(array)); } } { // 单表查询API也是可以的 Query<Person> q = QB.create(Person.class); Selects sel = QB.selectFrom(q); sel.columns(Person.Field.id, Person.Field.name, Person.Field.gender); List<Object[]> persons = db.selectAs(q, Object[].class); for (Object[] array : persons) { System.out.println(Arrays.toString(array)); } } } /** * 章节 8.1.1 直接指定返回类型 使用ResultTransformer来指定返回类型, * * @throws SQLException */ @Test public void testResult_transformer1() throws SQLException { { Query<Person> q = QB.create(Person.class); Selects sel = QB.selectFrom(q); sel.columns(Person.Field.id, Person.Field.name, Person.Field.gender); // 下面等同于 q.getResultTransformer().setResultType();之后再select List<String[]> results = db.selectAs(q,String[].class); if(results.size()>0){ String[] result=results.get(0); //按顺序输出 ID, NAME, GENDER三个字段 System.out.println(Arrays.toString(result)); } } { Query<Person> query = QB.create(Person.class); Selects select = QB.selectFrom(query); select.column(Person.Field.id); select.column(Person.Field.name).as("name"); select.column(Person.Field.gender); select.sqlExpression("'3'").as("grade"); select.column(Person.Field.created).as("dateOfBirth"); query.getResultTransformer().setResultType(Student.class); query.setMaxResult(1); Student st = db.load(query); } } /** * 特性演示 8.2.2 区分两种返回数据的规则 * * @throws SQLException */ @Test public void testResultType_columnAsArray2() throws SQLException { // 多表查询的时候,Object[]的返回类型默认是一张表的多个列拼成的对象作为数组元素, // 而不是每个列作为数组元素…… Query<Person> q = QB.create(Person.class); Join join = QB.innerJoin(q, QB.create(School.class)); List<Object[]> persons = db.selectAs(join, Object[].class); for (Object[] array : persons) { System.out.println("[" + array[0].getClass() + "," + array[1].getClass() + "]"); } // 可以这样写 join.getResultTransformer().setStrategy(PopulateStrategy.COLUMN_TO_ARRAY); persons = db.selectAs(join, Object[].class); for (Object[] array : persons) { System.out.println(Arrays.toString(array)); } // 这样,多表查询也可以以String[]形式返回值了 join.getResultTransformer().setStrategy(PopulateStrategy.COLUMN_TO_ARRAY); List<String[]> stringColumns = db.selectAs(join, String[].class); for (String[] array : stringColumns) { System.out.println(Arrays.toString(array)); } } /** * 特性演示 8.2.3 忽略@Column注解 * * @throws SQLException */ @Test public void testResultType_ignoreColumnAnnotation() throws SQLException { String sql = "select id as id, name as name, gender as gender from student"; // 将student表中查出的数据映射为Person对象。 NativeQuery<Person> nq = db.createNativeQuery(sql, Person.class); // 提示结果转换器,忽略@Column注解。 nq.getResultTransformer().setStrategy(PopulateStrategy.SKIP_COLUMN_ANNOTATION); Person person = nq.getSingleResult(); assertNotNull(person.getName()); } /** * 特性演示 8.2.4 自定义返回结果 */ @Test public void testResultMapper_1() throws SQLException{ Query<Student> q=QB.create(Student.class); q.getResultTransformer().addMapper(new Mapper<PersonResult>(){ @Override protected void transform(PersonResult obj, IResultSet rs) throws SQLException { obj.setBirthday(rs.getDate("DATE_OF_BIRTH")); obj.setPersonName(rs.getString("NAME")); if(obj.getBirthday()!=null){ //计算并设置年龄 int year=DateUtils.getYear(new Date()); obj.setAge(year-DateUtils.getYear(obj.getBirthday())); } } }); List<PersonResult> results = db.selectAs(q,PersonResult.class); if(results.size()>0){ PersonResult result = results.get(0); System.out.println(result.getPersonName()+"出生于"+result.getBirthday()+" 今年"+result.getAge()+"岁"); } } /** * 特性演示 8.2.4 自定义返回结果2 */ @Test public void testResultMapper_2() throws SQLException{ String sql="select t1.* , t2.* from t_person t1,school t2 " + "where t1.current_school_id=t2.id "; NativeQuery<Person> query = db.createNativeQuery(sql,Person.class); query.getResultTransformer().addMapper(Mappers.toResultProperty("currentSchool", School.class)); List<Person> result=query.getResultList(); for(Person person: result){ System.out.println(person.toString()+" ->"+person.getCurrentSchool()); } } /** * 特性演示 8.2.4 自定义返回结果 */ @Test public void testResultMapper_2_1() throws SQLException{ //由于两张表都有id列,这里必须重命名 String sql="select t1.* , t2.id as schoolid, t2.name from t_person t1,school t2 " + "where t1.current_school_id=t2.id "; NativeQuery<Person> query = db.createNativeQuery(sql,Person.class); //Mappers可以提供一些符合框架默认行为的映射器。 //因为schooldid是重命名的,所以不是框架的默认行为,于是要再adjust一下 query.getResultTransformer().addMapper( Mappers.toResultProperty("currentSchool", School.class).adjust("id", "schoolid")); List<Person> result=query.getResultList(); for(Person person: result){ System.out.println(person.toString()+" ->"+person.getCurrentSchool()); } Person zhangfei=result.get(0); Person liubei=result.get(2); assertEquals(zhangfei.getCurrentSchoolId(),liubei.getCurrentSchoolId()); assertNotSame(zhangfei.getId(), liubei.getId()); assertEquals(zhangfei.getCurrentSchool().getId(),liubei.getCurrentSchool().getId()); assertEquals(zhangfei.getCurrentSchool().getName(),liubei.getCurrentSchool().getName()); } /** * 特性演示 8.2.4 自定义返回结果 */ @Test public void testResultMapper_3() throws SQLException{ Query<Person> t1 = QB.create(Person.class); Query<Student> t2 = QB.create(Student.class); Join join = QB.innerJoin(t1, t2, QB.on(Person.Field.name, Student.Field.name)); Transformer transformer=join.getResultTransformer(); //因为是两表查询,默认返回的数组长度为2,为了增加一个返回对象需要将数组长度调整为3 transformer.setResultTypeAsObjectArray(3); transformer.addMapper(Mappers.toArrayElement(0, Student.class, "T2")); transformer.addMapper(Mappers.toArrayElement(1, Person.class, "T1")); //增加一个自定义的映射。 transformer.addMapper(new Mapper<Object[]>() { @Override protected void transform(Object[] obj, IResultSet rs) throws SQLException { PersonResult result=new PersonResult(); result.setPersonName(rs.getString("T1__NAME")); result.setBirthday(rs.getDate("T1__CREATED")); obj[2]=result; } }); List<Object[]> result = db.select(join, null); assertNotNull(result.get(0)[2]); //第二段案例: 清除映射器、忽略默认的映射规则 { Transformer t=join.getResultTransformer(); t.setResultType(Holder.class); //清除之前定义的映射器,因为之前已经在Transformer中添加了映射器。 t.clearMapper(); //忽略默认的映射规则 t.ignoreAll(); t.addMapper(new Mapper<Holder<PersonResult>>(){ @Override protected void transform(Holder<PersonResult> obj, IResultSet rs) throws SQLException { PersonResult result=new PersonResult(); result.setPersonName(rs.getString("T1__NAME")); result.setBirthday(rs.getDate("T1__CREATED")); obj.set(result); } }); List<Holder<PersonResult>> holders=db.select(join,null); for(Holder<PersonResult> h: holders){ System.out.println(h.get()); } } } }