package org.easyframe.tutorial.lesson4;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import jef.database.DbClient;
import jef.database.DbClientBuilder;
import jef.database.ORMConfig;
import jef.database.QB;
import jef.database.query.Query;
import org.easyframe.tutorial.lesson4.entity.DataDict;
import org.easyframe.tutorial.lesson4.entity.Person;
import org.easyframe.tutorial.lesson4.entity.School;
import org.junit.BeforeClass;
import org.junit.Test;
public class Case1 extends org.junit.Assert{
private static DbClient db ;
private static int firstId;
/**
* 准备
* @throws SQLException
*/
@BeforeClass
public static void setup() throws SQLException {
// ORMConfig.getInstance().setCacheLevel2(500);
// ORMConfig.getInstance().setDebugMode(true);
db = new DbClientBuilder().build();
db.dropTable(Person.class, School.class,DataDict.class);
db.createTable(Person.class, School.class,DataDict.class);
// 准备数据
School s1 = new School("天都中学");
School s2 = new School("嘉海一中");
School s3 = new School("天都大学附属中学");
db.batchInsert(Arrays.asList(s1, s2, s3));
ORMConfig.getInstance().setDebugMode(true);
DataDict dict1=new DataDict("USER.GENDER","M","男人");
DataDict dict2=new DataDict("USER.GENDER","F","女人");
DataDict dict3=new DataDict("USER.GENDER","U","不确定");
db.batchInsert(Arrays.asList(dict1,dict2,dict3));
Person p=new Person();
p.setName("孔明");
p.setCurrentSchoolId(1);
db.insert(p);
firstId=p.getId();
}
/**
* 这个案例表示“级联不破单表”,即级联模型不会影响原有的单表操作。
* 级联描述是一种可以后续随时添加删除的扩展描述,原先的单表操作模型保持不变。
*
* @throws SQLException
*/
@Test
public void testNonCascade() throws SQLException {
db.truncate(Person.class);
long t=System.currentTimeMillis();
Person p = new Person();
{
p.setName("玄德");
p.setCurrentSchoolId(1);
// 虽然Person对象中配置了级联关系。
// 但在EF-ORM中,级联关系是在保证了单表模型完整可用的基础上,补充上去的一种附属描述
// 因此非级联操作一样可用。
db.insert(p);
}
//查出记录
p = db.load(p);
//单表更新
p.setCurrentSchoolId(2);
p.setName("云长");
db.update(p);
//单表删除
db.delete(p);
System.out.println(System.currentTimeMillis()-t);
}
/**
* 级联情况下简单的CRUD
* @throws SQLException
*/
@Test
public void testCascade() throws SQLException{
School school=db.load(new School("天都中学"));
int personId;
{
Person p = new Person();
p.setName("翼德");
p.setCurrentSchool(school);
db.insertCascade(p);
personId=p.getId();
}
{
//查出记录
Person p=db.load(new Person(personId));
System.out.println(p.getCurrentSchoolId()+":"+p.getCurrentSchool().getName());
assertEquals("天都中学",p.getCurrentSchool().getName());
//更新为另一学校
p.setCurrentSchool(new School("天都外国语学校"));
db.updateCascade(p);//外国语学校是新增的,在更新语句执行之前会先做插入School表操作。
System.out.println("天都外国语学校 ID = "+p.getCurrentSchoolId()+" = "+p.getCurrentSchool().getId());
//再使用单表更新方式,更新回原来的学校
p.setCurrentSchoolId(school.getId());
db.update(p);
//删除该学生
db.deleteCascade(p);
}
}
/**
* 这个案例演示级联选项是可以关闭的
* @throws SQLException
*/
@Test
public void testNonCasecadeLoad() throws SQLException{
int personId;
{
Person p = new Person();
p.setName("玄德");
p.setCurrentSchoolId(1);
db.insert(p);//插入一条记录
personId=p.getId();
}
Person p=db.load(Person.class, personId);
System.out.println(p.getCurrentSchool());
assertNotNull(p.getCurrentSchool());
//默认情况下, select()和load()方法都是级联操作,因此能查出关联的School对象
//不过级联的开关可以自由控制——
{
Person query=new Person();
query.setId(personId);
//设置为非级联查询
query.getQuery().setCascade(false);
//等效于...
//query.getQuery().getResultTransformer().setLoadVsMany(false);
//query.getQuery().getResultTransformer().setLoadVsOne(false);
p= db.load(query);
System.out.println(p.getCurrentSchool());
assertNull(p.getCurrentSchool()); //关闭级联开关不做级联查询了,所以School对象得不到了
assertEquals(1, p.getCurrentSchoolId());
}
}
/**
* 这个案例演示,仅引用关联对象中一个字段的场景
*
* 用Person的性别为例
* @throws SQLException
*/
@Test
public void testGetFieldFromManyToOne() throws SQLException{
//FIXME ,当不使用外连接时,FileCondition无效的问题。
ORMConfig.getInstance().setCacheDebug(true);
//准备数据
Person p1=new Person();
p1.setName("孟德");
p1.setGender('M'); //男性为M 女性为F
p1.setDictType("USER");
Person p2=new Person();
p2.setName("貂蝉");
p2.setGender('F');
p2.setDictType("USER");
db.insert(p1);
db.insert(p2);
{
//查出数据
Query<Person> query=QB.create(Person.class);
query.setCascadeViaOuterJoin(true);
query.addCondition(QB.notNull(Person.Field.gender));
query.orderByAsc(Person.Field.gender);
List<Person> p=db.select(query);
assertEquals("女人", p.get(0).getGenderName());
assertEquals("男人", p.get(1).getGenderName());
}
{
Query<Person> query=QB.create(Person.class);
query.setCacheable(false);
query.setCascadeViaOuterJoin(true);
query.addCondition(QB.notNull(Person.Field.gender));
query.orderByAsc(Person.Field.gender);
List<Person> p=db.select(query);
assertEquals("女人", p.get(0).getGenderName());
assertEquals("男人", p.get(1).getGenderName());
}
}
/**
* 这个案例演示,可以将级联关系设置为延迟加载的。
* 运行此案例前,请先修改Person.java的代码,设置
* <pre><code>
* @ManyToOne(targetEntity = School.class,fetch=FetchType.LAZY)
* </code></pre>
*
* @throws SQLException
*/
@Test
public void testLazyLoad() throws SQLException{
Person query=new Person();
query.setId(firstId);
Person p=db.load(query);
System.out.println("接下来观察调用get方法后,才会输出加载School的SQL语句。");
p.getCurrentSchool();
//请观察输出的SQL语句,
}
/**
* 这个案例演示,ManyToOne的关系的两种实现区别
* 1、通过外连接一次加载
* 2、分次加载,当我们setCascadeViaOuterJoin(false)的时候,即采用分次加载
* 。(默认情况下,使用单次访问数据库的外连接加载方式。)
*
* 用Person的性别为例
* @throws SQLException
*/
@Test
public void testNonOuterJoin() throws SQLException{
Person query=new Person();
query.setId(firstId);
query.getQuery().setCascadeViaOuterJoin(false); //改变默认行为,不使用外连接。
Person p=db.load(query);
p.getCurrentSchool();
p.getGenderName();
//请观察输出的SQL语句,
}
/**
* 可以动态的对级联对象设置过滤条件。
* 通过addCascadeCondition方法。
* @throws SQLException
*/
@Test
public void testCascadeCondition() throws SQLException{
Query<Person> query=QB.create(Person.class);
query.setCascadeViaOuterJoin(true);
query.addCondition(QB.eq(Person.Field.id,firstId));
query.addCascadeCondition(QB.matchAny(School.Field.name, "清华"));
db.select(query);
}
}