# 数据模型
BeetlSQL的参数和出参支持POJO和Map。一般来说POJO跟容易维护,而Map不容易维护,尤其是类型,很可能不同数据库,Map的Value类型还可能不一样。而POJO映射则会强制转化为POJO定义的类型,或者使用注解,RowMapper,ResultSetMapper等方式等进一步扩展
BeetlSQL推荐使用POJO作为数据模型
## POJO
POJO的定义是普通java对象(相对于JavaEE的EJB来说的),java对象需要准守JavaBean规范,即提供getter和setter方法。如下是一个符合BeetlSQL的POJO
```java
public class UserData{
Integer id;
String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
```
下面的代码则不是POJO
```java
public class UserData{
public Integer id;
public String name;
}
```
下面的代码也不是POJO
```java
public class UserData{
Integer id;
public Integer getId() {
return id;
}
public UserData setId(Integer id) {
this.id = id;
return this
}
}
```
如果使用lombok,则只需要使用@Data注解
```java
@Data
public class UserData{
Integer id;
String name;
}
```
## 交集
这是一个非常重要的概念。BeetlSQL 在操作数据库的时候,默认情况只会处理POJO与数据库表(视图)的交集,比如,数据库表有id,user_name 俩个字段
而Java的POJO 有id和name。 因此(除非你使用@Cloumn说明),只有POJO的id属性和表的id字段对应上,这将作为BeetlSQL的所有操作基础元数据
当你调用insert方法的时候,POJO的id属性将被插入到id列,但name属性不做任何操作。
当你调用select方法的时候POJO的属性name无法赋值
## @Table 注解
当要进行插入或者更新操作的时候,类名通过NameConversion隐喻了表名,也可使用@Table注解说明表名字
```java
@Table(name="sys_user")
@Data
public static class UserData{
}
```
如果表在其他schema或者catalog里,可以加上前缀
```java
@Table(name="das10.sys_user")
@Data
public static class UserData{
}
```
@Table注解可以使用表达式,以实现动态分表
```java
static final String USER_TABLE="${toTable('sys_user',id)}";
@Data
@Table(name = USER_TABLE)
public class MyUser {
@AssignID
private Integer id;
private String name;
}
```
toTable是一个自定义函数,可以查看源码S6MoreDatabase,或者查看《BeetlSQL3 多库使用》
如果不是更新或者插入,而只是映射查询结果,则不需要@Table,你可以定义任意多的POJO来映射结果集,BeetlSQL3默认情况会采用POJO属性和结果集的交集来映射。比如MyUser对象,只有id和name,那么查询结果中的列名department_id不做映射
## @ Column 注解
同@Table一样,如果NameConversion无法满足,可以使用@Column来标识属性对应的列名
```java
@Table(name="sys_user")
public class TestUser {
@Column("id")
@AutoID
Integer myId;
@Column("name")
String myName;
Integer departmentId;
}
```
属性departmentId并未使用注解,这说明符合NameConversion
## 主键
@AutoID,作用于属性字段或者getter方法,告诉beetlsql,这是自增主键,对应于数据自增长
```java
@AutoID
Integer myId;
```
@AssignID,作用于属性字段或者getter方法,告诉beetlsql,这是程序设定
```java
@AssignID
Integer id;
```
代码设定主键允许像@AssignID 传入id的生成策略以自动生成序列,BeetlSQL默认提供了一个snowflake算法,一个用于分布式环境的id生成器([https://github.com/twitter/snowflake](https://github.com/twitter/snowflake))
```java
@AssignID("simple")
@AssignID()
Long id;
```
simple 是beetlsql提供的一个默认的snowflake实现,你可以实现自己的id生成策略
```java
sqlManager.addIdAutonGen("uuid", new IDAutoGen(){
@Override
public Object nextID(String params) {
return UUID.randomUUID().toString();
}
});
```
```java
@AssignID("uuid")
String id;
```
- @SeqID(name="xx_seq"),告诉beetlsql,这是序列主键,目前只有H2,Oracle和Postgres或者DB2使用序列主键,以源码单元测试为例子,如下DeviceDetail具有id,序列名称是`label_sequence`
```java
@Data
public abstract class BaseSeqIdEntity<ID> extends BaseEntity implements Serializable{
@SeqID(name="label_sequence")
protected ID id;
}
@Data
@Table(name="device_detail")
public class DeviceDetail extends BaseSeqIdEntity<Integer>{
String json;
}
```
IdTest的seqIdTest如下
```java
public class IdTest extends BaseTest {
@Test
public void seqIdTest(){
DeviceDetail data = new DeviceDetail();
data.setJson("{}");
sqlManager.insert(data);
Assert.assertNotNull(data.getId());
System.out.println(data);
}
}
```
执行后,可以看到H2的输出
```java
┏━━━━━ Debug [deviceDetail.$insert] ━━━
┣ SQL: insert into device_detail (ID ,JSON ) values (NEXT VALUE FOR label_sequence ,? )
┣ 参数: [{}]
┣ 位置: org.beetl.sql.id.IdTest.seqIdTest(IdTest.java:47)
┣ 时间: 7ms
┣ 更新: [1]
┗━━━━━ Debug [deviceDetail.$insert] ━━━
```
H2Style.getSeqValue返回了序列名称对应的求值语句,Oralce,Postgres类似,如下是DbStyle的getSeqValue实现
```java
public class H2Style extends AbstractDBStyle {
@Override
public String getSeqValue(String seqName) {
return "NEXT VALUE FOR "+seqName;
}
}
public class OracleStyle extends AbstractDBStyle {
@Override
public String getSeqValue(String seqName) {
return seqName+".nextval";
}
}
public class OracleStyle extends AbstractDBStyle {
@Override
public String getSeqValue(String seqName) {
return "nextval('" + seqName + "')";
}
}
```
> 对于支持多种数据库的,这些annotation可以叠加在一起,但作为跨库更好的选择是使用@Assign,并自定义个id生成策略
## RowMapper
BeetlSQL完成默认的映射,你可以自定义一个RowmMapper子类,完成额外的映射
```java
public interface RowMapper<T> {
/**
*
* @param obj 正常处理后的对象
* @param rs 结果集
* @param rowNum 处理的记录位置(第几条记录):可以只针对某一条记录做特殊处理
* @param config 注解相关配置,参考 {@link ProviderConfig}
* @throws SQLException
* @return T
*/
T mapRow(ExecuteContext ctx, Object obj, ResultSet rs, int rowNum, Annotation config) throws SQLException;
}
```
RowMapper会在BeetlSQL默认映射结果集的基础上做额外处理,比如,有些未映射的也可以通过`ResultSet rs` 中调用获取
```java
public static class MyRowMapper implements RowMapper<UserVo>{
@Override
public UserVo mapRow(ExecuteContext ctx, Object obj, ResultSet rs, int rowNum, Annotation config) throws SQLException {
//内置的映射已经完成
UserVo vo = (UserVo)obj;
//额外取得结果集
String col = rs.getString("col");
vo.setExtraAttribute(col);
return vo;
}
}
```
有俩种方式可以使用RowMapper,一种是通过在POJO上加上注解@RowProvider
```java
@RowProvider(MyRowMapper.class)
public class UserVo2 {
//忽略其他属性
public void setExtraAttribute(String col){}
}
```
另外一种是SQLManager.rowMapper 方法,临时设置一次当前查询使用RowMapper(这种方式不常用)
```java
sqlManager.rowMapper(MyRowMapper.class).select(sqlId,xxxx.class,paras);
```
当查询结果返回后,rowMapper使用结束。除非再次调用rowMapper方法
## ResultSetMapper
如果想自己完全掌控结果集映射,可以使用ResultSetMapper,定义如下
```java
public interface ResultSetMapper<T> {
/**
* 将数据库查询结果集ResultSet映射到一个对象上,对象通过target指定
* @param ctx
* @param target
* @param resultSet
* @param config 实现了ProviderConfig注解的注解,如果没有,则为空
* @return
*/
public List<T> mapping(ExecuteContext ctx, Class target, ResultSet resultSet, Annotation config) throws SQLException;
}
```
ExecuteContext代表了执行上下文,比如SqlId,当前的SQLManager,入参等,一般很少需要关注,除非有些高级需求,比如BeetlSQL提供的JSON映射就是用到了ExecuteContext
一个简单的实现如下
```java
public class MyResultSetMapper implements ResultSetMapper<ResultSetObject>{
@Override
public List<ResultSetObject> mapping(ExecuteContext ctx, Class target, ResultSet resultSet, Annotation config) throws SQLException {
List<ResultSetObject> list = new ArrayList<>();
while(resultSet.next()){
ResultSetObject obj = new ResultSetObject();
obj.setMyId(resultSet.getInt("id"));
obj.setMyName(resultSet.getString("name"));
list.add(obj);
}
return list;
}
}
```
有俩种方法使用ResultSetMapper,第一种在POJO使用注解
```java
@Data
@ResultProvider(MyResultSetMapper.class)
public class ResultSetObject{
private Integer myId;
private String myName;
}
```
或者使用SQLManager.resultSetMapper(Class resultSetMapperClass),临时设置一次当前查询采用的映射类
## 混合模型
混合模型。兼具灵活性和更好的维护性。POJO可以实现Tail(尾巴的意思),或者继承TailBean,这样查询出的ResultSet 除了按照pojo进行映射外,无法映射的值将按照列表/值保存。如下一个混合模型:
```java
/*混合模型*/
public User extends TailBean{
private int id ;
private String name;
private int roleId;
/*以下是getter和setter 方法*/
}
```
对于sql语句:
```markdown
selectUser
===
select u.*,r.name r_name from user u left join role r on u.roleId=r.id .....
```
执行查询的时候
```java
List<User> list = sqlManager.select(sqlId,User.class,paras);
for(User user:list){
System.out.println(user.getId());
System.out.println(user.get("rName"));
}
```
程序可以通过get方法获取到未被映射到pojo的值,也可以在模板里直接 ${user.rName} 显示(对于大多数模板引擎都支持)
另外一种更自由的实现混合模型的方法是在目标Pojo上采用注解@Tail,如果注解不带参数,则默认会调用set(String,Object) 方法来放置额外的查询属性,否则,依据注解的set参数来确定调用方法
```java
@Tail(set="addValue")
public class User {
private Integer id ;
private Integer age ;
public User addValue(String str,Object ok){
ext.put(str, ok);
return this;
}
```
## Json配置映射
类似MyBatis通过xml提供映射,BeetlSQL3通过实现ResultSetMapper,提供了一个json格式映射
```java
private static final String USER_MAPPING = "{'id':'id','name':'name','deptName':'dept_name'}";
@Data
@ResultProvider(JsonConfigMapper.class)
@JsonMapper(USER_MAPPING)
public static class UserInfo {
Integer id;
String name;
String deptName;
}
```
对于UserInfo,使用了BeetlSQL3提供的JsonConfigMapper对象,JsonConfigMapper会读取@JsonMapper作为配置映射参数,这样,如果查询的SQL结果集是
```
id,name,detp_name
```
则会按照`USER_MAPPING`的配置映射到各自属性上
> @JsonMapper 实现了@ProviderConfig()注解,因此,这注解将会传给JsonConfigMapper。了解BeetlSQL3注解如何实现,可以参考《源码解读》
如果需要一对多的映射,也可以使用
```java
private static final String DEPT_MAPPING = "{'id':'id','name':'name','users':{'id':'u_id','name':'u_name'}}";
@Data
@ResultProvider(JsonConfigMapper.class)
@JsonMapper(DEPT_MAPPING)
public static class DepartmentInfo {
Integer id;
String name;
List<UserInfo> users;
}
```
对于DEPT_MAPPING配置,如果结果集满足
```sql
id,name,u_id,u_name
```
则可以进行映射,并且,u_id,u_name,赋值给UserInfo对象, 此对象合并到**相同(id,name)**的DepartmentInfo的users属性上
JsonConfigMapper可以进行任意复杂的映射。 并将结果集合并
@JsonMapper提供了json配置,也可以指定一个sqlId作为配置,因此配置可以放到markdown文件里
```java
@ResultProvider(JsonConfigMapper.class)
//@JsonMapper(
// "{'id':'id','name':'name','users':{'id':'u_id','name':'u_name'}}")
@sonMapper(resource ="dept.departmentJsonMapping")
public class MyDepartment {
Integer id;
String name;
List<MyUser> users;
}
```
dept.md内容如下
```markdown
departmentJsonMapping
===
* MyDepartment
```json
{
"id":"id",
"name":"name",
"users":
{
"id":"u_id",
"name":"u_name"
}
}
```
```
## Json自动映射
如果查询结果集跟java类定义匹配,则不需要显示的json配置,可以AutoJsonMapper
```java
@Data
@ResultProvider(AutoJsonMapper.class)
public class MyUserView {
Integer id;
String name;
DepartmentEntity dept;
}
```
如上配置,可以自动映射如下查询结果
```java
String sql = "select u.id ,u.name ,d.id `dept.id`,d.name `dept.name` " +
" from sys_user u left join department d on d.id=u.department_id";
SQLReady ready = new SQLReady(sql);
List<MyUserView> list = sqlManager.execute(ready,MyUserView.class);
```
之所以成为AutoJsonMapper,是因为AutoJsonMapper会解析POJO类,生成一个json配置,类似如下
```json
{
"id":"id",
"name":"name",
"dept":
{
"id":"dept.id",
"name":"dept.name"
}
}
```
## XML映射
未完成,期待3的某个版本实现,实现方式同Json配置映射,希望有人看了JsonConfigMapper或者AutoJsonMapper能参考实现一个
## 自动Fetch
有时候查询结果出来后需要自动加载额外的数据,类似Hibernate 的关系映射。BeetlSQL3也支持这种自动抓取。不同hibernate的是,他不强制要求有外键关系
> 越来越多数据库设计不考虑外键,这样能提升一些性能。系统维护也好维护。
自动抓取通过@Fetch注解,提醒BeetlSQL3在执行完查询操作后有自动抓取需要完成,BeetlSQL3会解析此POJO的属性,如果一旦有@FetchMany或者@FetchOne,或者@FetchSql,则会执行查询操作
```java
@Data
@Table(name="sys_order")
@Fetch(level =2)
public class CustomerOrder {
@AutoID
Integer id;
String name;
Integer customerId;
@FetchOne(value="customerId")
Customer customer;
}
@Data
@Fetch(level = 2)
@Table(name="sys_customer")
public class Customer {
@AutoID
Integer id;
String name;
@FetchMany("customerId")
List<CustomerOrder> order;
}
@Table(name="sys_order")
@Fetch(level =2)
public class CustomerOrder2 {
@AutoID
Integer id;
String name;
Integer customerId;
@FetchSql("select * from sys_customer where id =#{customerId}")
Customer customer;
@FetchSql("select * from sys_customer s where s.id =#{customerId} order by s.id desc")
List<Customer> customers;
}
```
@Fetch的level属性表示抓取数据的深度,默认是一层,CustomerOrder设定为2,则不仅仅会自动抓取Customer数据,也会抓取Customer的CustomerOrder数据。如果CustomerOrder设定为3,那么,还会从CustomerOrder再次抓取Customer,实现3层抓取
> BeetlSQL3在Fetch过程中把已经抓取的过数据放入内存里,如果类似数据一旦曾经抓取过,则不会再从数据库里获取。因此不需要担心出现死循环.同时,缓存有利于性能优化,不需要查询数据库
@FetchOne 表示抓取一个,其value值是POJO的一个属性名,该属性名对应的值作为需要·抓取对象的主键,因此CustomerOrder的@FetchOne注解表明了需要使用CustomerOrder.customerId属性值作为主键来查询Customer。因此BeetlSQL3会发起类似如下查询
```java
Integer customerId = getAttrValue(customerOrderIns,"customerId")
Customer customer = sqlMqnager.unique(Customer,customerId);
```
对于Customer对象,需要自动抓取多个CustomerOrder,注解@FetchMany("customerId") 告诉BeetlSQL3.启用模板查询功能查询CustomerOrder,模板的key是“customerId”(也就是CustomerOrder属性customerId),值是POJO的主键,就是Customer.id.因此BeetlSQL会发起类似入如下查询
```java
Integer customerId = getPrimakeyValue(customerIns);
CustomerOrder template = new CustomerOrder();
tempalte.setCustomerId(customerId);
List<CustomerOrder> list = sqlManager.template(tempalte);
```
BeetlSQL3 的FetchOne操作会进行合并查询,比如查询所有CustomerOrder
```java
List<CustomerOrder> orders = sqlManager.all();
```
在BeetlSQL3 进行自动抓取的时候,并不会逐一抓取Customer对象,而是调用sqlManager.selectByIds 一次性抓取所有Customer,提高性能呢
当使用自动Fetch,设置level=2的时候,出现A引用B,B又引用A的时候,需要特别设计A和B对象的hashcode方法和equals方法,避免出现无限循环,比如
```java
@Fetch(level = 2)
@Table(name="sys_customer")
@EqualsAndHashCode(of="id")
public class Customer {
@AutoID
Integer id;
String name;
@FetchMany("customerId")
List<CustomerOrder> order;
}
```
如果没有`@EqualsAndHashCode(of="id")` 那么Customer的hashcode方法包括CustomerOrder,而CustomerOrder又包含Customer,这样导致hashcode无需循环,出现StackOverflowError。 这并不是BeetlSQL的问题
## AttributeConvert
可以自定义一个属性注解,BeetlSQL上遇到此属性注解,将按照属性注解的执行类去执行映射,比如对手机号码的入库加密,出库解密。比如对JSON对象序列化成字符串到数据库,然后从数据库反序列成成对象。同其他BeetlSQL扩展注解机制类似,实现一个扩展注解,需要使用@Builder注解申明其执行类
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.FIELD})
@Builder(Base64Convert.class)
public static @interface Base64 {
}
```
如上申明一个@Encrypt,用于字段在入库加密,出库解密。其实现类使用@Builder注解申明,本例其执行类是Base64Convert。
执行类必须是一个AttributeConvert的子类
```java
public static class Base64Convert implements AttributeConvert {
Charset utf8 = Charset.forName("UTF-8");
public Object toDb(ExecuteContext ctx, Class cls, String name, Object pojo) {
String value= (String) BeanKit.getBeanProperty(dbValue,name);
byte[] bs = java.util.Base64.getEncoder().encode(value.getBytes(utf8));
return new String(bs,utf8);
}
public Object toAttr(ExecuteContext ctx, Class cls, String name, ResultSet rs, int index) throws SQLException {
String value = rs.getString(index);
return new String(java.util.Base64.getDecoder().decode(value),utf8);
}
}
```
toDb方法用于将属性转化为列,pojo指入库的POJO对象,name是指其属性名称,可以调用BeetlSQL3提供的类BeanKit.getBeanProperty获取对象属性值
toAttr将数据库转化为属性
```java
@Table(name="sys_user")
@Data
public class UserData{
@AutoID
Integer id;
@Base64
String name;
}
```
如下是定义了一个@Update注解
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.FIELD})
@Builder(UpdateTimeConvert.class)
public @interface UpdateTime {
}
public class UpdateTimeConvert implements AttributeConvert {
@Override
public Object toDb(ExecuteContext ctx, Class cls,String name, Object pojo){
Date now = new Date();
BeanKit.setBeanProperty(pojo,now,name);
return now;
}
}
```
这样,在每次入库操作的时候,都取得最新的时间。并调用BeanKit.setBeanProperty赋值给pojo对象,并返回当前时间
。BeetlSQL3通过返回的当前时间做入库操作,因此调用BeanKit.setBeanProperty 不是必须操作。但POJO对象还需要有一个一致的值。
## BeanConvert
可以为POJO定义一个注解,在sql准备参数前,调用此API,得到一个新Bean,用于参数设定。BeanConvert定义如下
```java
@Plugin
public interface BeanConvert {
/**
* 返回入库之前的对象
* @param ctx
* @param obj
* @param an 注解信息,可以提供额外参数
* @return
*/
default Object before(ExecuteContext ctx, Object obj, Annotation an){
return obj;
}
/**
* 返回查询结果后的对象
* @param ctx
* @param obj
* @param an
* @return
*/
default Object after(ExecuteContext ctx, Object obj, Annotation an){
return obj;
}
}
```
比如以AttributeConvert的例子作为说明,可以定义如下BeanEncrypt, 其执行类BeanStringConvert, 注解有个attr方法,标识需要加密的字段
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Builder(BeanStringConvert.class)
public @interface BeanEncrypt {
String attr();
}
```
BeanStringConvert的实现如下(仅仅简单修改了需要加密的字段,添加一个时间戳)
```java
public class BeanStringConvert implements BeanConvert{
public Object before(ExecuteContext ctx, Object obj, Annotation an){
BeanEncrypt beanEncrypt = (BeanEncrypt)an;
String attrName = beanEncrypt.attr();
String attrValue = (String)BeanKit.getBeanProperty(obj,attrName);
String encryptAttrValue = attrValue+"-"+System.currentTimeMillis();
BeanKit.setBeanProperty(obj,encryptAttrValue,attrName);
return obj;
}
public Object after(ExecuteContext ctx, Object obj, Annotation an){
BeanEncrypt beanEncrypt = (BeanEncrypt)an;
String attrName = beanEncrypt.attr();
String encryptAttrValue = (String)BeanKit.getBeanProperty(obj,attrName);
String attrValue = encryptAttrValue.split("-")[0];
BeanKit.setBeanProperty(obj,attrValue,attrName);
return obj;
}
}
```
```java
@Table(name="sys_user")
@Data
@BeanEncrypt( attr="name")
public static class UserEntity2{
@Auto
Long id ;
String name;
}
```
## 枚举
BeetlSQL3默认情况会调用枚举的name方法转化为字符串,存入数据库。当从数据库取出字符串的时候,调用枚举的valueOf方法得到其枚举
```java
public class UserData{
@AutoID
Integer id;
Name name;
}
/*使用枚举名存库*/
enum Name{
Li,
Zhang;
}
```
BeetlSQL3也支持自定义枚举存入数据库的值,使用@EnumValue标注在枚举的属性字段上,如下枚举Name2,取值是属性`str`
```java
public enum Name2{
Li("li"),
Zhang("zhang");
@EnumValue
String str;
Name2(String str){
this.str = str;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
```
如果枚举来自第三方,无法使用@EnumValue,则可以使用@EnumMapping,如上Name2如果来自第三方,则可以在POJO中@EnumValue
```java
@Table(name="sys_user")
@Data
public static class UserData3{
@AutoID
Integer id;
@EnumMapping("str")
Name2 name;
}
```
> 关于枚举,可以参考源码单元测试EnumSelectTest
## 其他注解
* @UpdateIgnore 作用于属性上,当使用内置的更新语句的时候,会忽略此字段
* @InsertIgnore 作用于属性上,当使用内置的插入语句的时候,会忽略此字段
* @LogicDelete,作用在属性上,告诉BeetlSQL,deleteById语句 生成更新语句,并设置此属性字段为LogicDelete指定的值
```java
@Data
@Table(name="sys_user")
public class SysUser{
@AutoId
Integer id;
String name;
@LogicDelete(1)
Integer flag;
}
```
逻辑删除改变了deleteById的sql,但对于其他内置查询,没有把逻辑删除作为过滤条件,依然能查询出来。这点不同于mybatis-plus。如果需要过滤,请参考扩展BeetlSQL3
* @Version
注解@Version作用在类型为int,long的属性或者getter方法上,用于乐观锁实现。
~~~java
public class Credit implements Serializable{
private Integer id ;
private Integer balance ;
@Version
private Integer version ;
~~~
当调用内置的updateById,或者updateTemlateById的时候,被@Version注解的字段将作为where条件的一部分
~~~
┏━━━━━ Debug [credit._gen_updateTemplateById] ━━━
┣ SQL: update `credit` set `balance`=?, `version`=`version`+1 where `id` = ? and `version` = ?
┣ 参数: [15, 1, 5]
┣ 位置: org.beetl.sql.test.QuickTest.main(QuickTest.java:38)
┣ 时间: 4ms
┣ 更新: [1]
┗━━━━━ Debug [credit._gen_updateTemplateById] ━━━
~~~
* @View注解
在BeetlSQL内置查询语句里,返回的结果集是POJO和列的交集,使用@View注解,可以进一步限定内置SQL语句需要返回的列
如下MyUser对象,有三个字段,id和name,以及photo。当sqlManager发起内置的查询的时候,这三个字段都会返回结果集,如果你想在某些查询下排除photo字段,可以使用@View
```java
@Data
@Table(name="user")
public class MyUser {
static interface Simple{}
static interface Complex{}
@AssignID
@View(Simple.class,Complex.class)
private Integer id;
@View(Simple.class)
private String name;
@View(Complex.class)
private byte[] photo;
}
```
如上name属性,当view是Simple.class的时候将返回,photo属性则只在view是Complex.class的返回。 id则总是返回。
SQLManager.viewType指定此次查询的view,如下指定Simple
```java
MyUser cacheItem = SQLManager.viewType(MyUser.Simple).single(MyUser.class,1)
```
如下指定Complex
```java
MyUser userWithPohot = SQLManager.viewType(MyUser.Complex).single(MyUser.class,1)
```
* @TargetSQLManager
如果SQLManager是ConditionalSQLManager子类,则可以在POJO中指明使用哪个SQLManager
```java
@Table(name="sys_user")
@TargetSQLManager("sysSqlmanager")
@Data
public class DbUser1 {
@AssignID
private Long id;
private String name;
}
```
由于ConditionalSQLManager涉及了多库,因此这部分将在《BeetlSQL3 多库使用》信息说明
> 源码S6MoreDatabase.conditional 演示了ConditionalSQLManager使用