
com.jfinal.plugin.activerecord.Model Maven / Gradle / Ivy
/**
* Copyright (c) 2011-2017, James Zhan 詹波 ([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jfinal.plugin.activerecord;
import com.jfinal.plugin.activerecord.cache.ICache;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
import java.util.Map.Entry;
import static com.jfinal.plugin.activerecord.DbKit.NULL_PARA_ARRAY;
/**
* Model.
*
* A clever person solves a problem.
* A wise person avoids it.
* A stupid person makes it.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class Model implements Serializable {
private static final long serialVersionUID = -990334519496260591L;
public static final int FILTER_BY_SAVE = 0;
public static final int FILTER_BY_UPDATE = 1;
public M dao() {
attrs = DaoContainerFactory.daoMap;
modifyFlag = DaoContainerFactory.daoSet;
return (M) this;
}
/**
* Attributes of this model
*/
private Map attrs = getAttrsMap(); // getConfig().containerFactory.getAttrsMap(); // new HashMap();
private Map getAttrsMap() {
Config config = _getConfig();
if (config == null)
return DbKit.brokenConfig.containerFactory.getAttrsMap();
return config.containerFactory.getAttrsMap();
}
/**
* Flag of column has been modified. update need this flag
*/
private Set modifyFlag;
/*
private Set getModifyFlag() {
if (modifyFlag == null)
modifyFlag = getConfig().containerFactory.getModifyFlagSet(); // new HashSet();
return modifyFlag;
}*/
Set getModifyFlag() {
if (modifyFlag == null) {
Config config = _getConfig();
if (config == null)
modifyFlag = DbKit.brokenConfig.containerFactory.getModifyFlagSet();
else
modifyFlag = config.containerFactory.getModifyFlagSet();
}
return modifyFlag;
}
private String configName = null;
/**
* Switching data source, dialect and all config by configName
*/
public M use(String configName) {
this.configName = configName;
return (M) this;
}
protected Config _getConfig() {
if (configName != null)
return DbKit.getConfig(configName);
return DbKit.getConfig(getUsefulClass());
}
/*
private Config getConfig() {
return DbKit.getConfig(getUsefulClass());
}*/
private Table getTable() {
return TableMapping.me().getTable(getUsefulClass());
}
/**
* Set attribute to model.
*
* @param attr the attribute name of the model
* @param value the value of the attribute
* @return this model
* @throws ActiveRecordException if the attribute is not exists of the model
*/
public M set(String attr, Object value) {
Table table = getTable(); // table 为 null 时用于未启动 ActiveRecordPlugin 的场景
if (table != null && !table.hasColumnLabel(attr)) {
throw new ActiveRecordException("The attribute name does not exist: \"" + attr + "\"");
}
attrs.put(attr, value);
getModifyFlag().add(attr); // Add modify flag, update() need this flag.
return (M) this;
}
// public static transient boolean checkPutKey = true;
/**
* Put key value pair to the model without check attribute name.
*/
public M put(String key, Object value) {
/*
if (checkPutKey) {
Table table = getTable(); // table 为 null 时用于未启动 ActiveRecordPlugin 的场景
if (table != null && table.hasColumnLabel(key)) {
throw new ActiveRecordException("The key can not be attribute name: \"" + key + "\", using set(String, Object) for attribute value");
}
}*/
attrs.put(key, value);
return (M) this;
}
/**
* Put map to the model without check attribute name.
*/
public M put(Map map) {
attrs.putAll(map);
return (M) this;
}
/**
* Put other model to the model without check attribute name.
*/
public M put(Model model) {
attrs.putAll(model._getAttrs());
return (M) this;
}
/**
* Put record to the model without check attribute name.
*/
public M put(Record record) {
attrs.putAll(record.getColumns());
return (M) this;
}
/**
* Convert model to record.
*/
public Record toRecord() {
return new Record().setColumns(_getAttrs());
}
/**
* Get attribute of any mysql type
*/
public T get(String attr) {
return (T) (attrs.get(attr));
}
/**
* Get attribute of any mysql type. Returns defaultValue if null.
*/
public T get(String attr, Object defaultValue) {
Object result = attrs.get(attr);
return (T) (result != null ? result : defaultValue);
}
/**
* Get attribute of mysql type: varchar, char, enum, set, text, tinytext, mediumtext, longtext
*/
public String getStr(String attr) {
// return (String)attrs.get(attr);
Object s = attrs.get(attr);
return s != null ? s.toString() : null;
}
/**
* Get attribute of mysql type: int, integer, tinyint(n) n > 1, smallint, mediumint
*/
public Integer getInt(String attr) {
Number n = (Number) attrs.get(attr);
return n != null ? n.intValue() : null;
}
/**
* Get attribute of mysql type: bigint, unsign int
*/
public Long getLong(String attr) {
Number n = (Number) attrs.get(attr);
return n != null ? n.longValue() : null;
}
/**
* Get attribute of mysql type: unsigned bigint
*/
public java.math.BigInteger getBigInteger(String attr) {
return (java.math.BigInteger) attrs.get(attr);
}
/**
* Get attribute of mysql type: date, year
*/
public java.util.Date getDate(String attr) {
return (java.util.Date) attrs.get(attr);
}
/**
* Get attribute of mysql type: time
*/
public java.sql.Time getTime(String attr) {
return (java.sql.Time) attrs.get(attr);
}
/**
* Get attribute of mysql type: timestamp, datetime
*/
public java.sql.Timestamp getTimestamp(String attr) {
return (java.sql.Timestamp) attrs.get(attr);
}
/**
* Get attribute of mysql type: real, double
*/
public Double getDouble(String attr) {
Number n = (Number) attrs.get(attr);
return n != null ? n.doubleValue() : null;
}
/**
* Get attribute of mysql type: float
*/
public Float getFloat(String attr) {
Number n = (Number) attrs.get(attr);
return n != null ? n.floatValue() : null;
}
public Short getShort(String attr) {
Number n = (Number) attrs.get(attr);
return n != null ? n.shortValue() : null;
}
/**
* Get attribute of mysql type: bit, tinyint(1)
*/
public Boolean getBoolean(String attr) {
return (Boolean) attrs.get(attr);
}
/**
* Get attribute of mysql type: decimal, numeric
*/
public java.math.BigDecimal getBigDecimal(String attr) {
return (java.math.BigDecimal) attrs.get(attr);
}
/**
* Get attribute of mysql type: binary, varbinary, tinyblob, blob, mediumblob, longblob
*/
public byte[] getBytes(String attr) {
return (byte[]) attrs.get(attr);
}
/**
* Get attribute of any type that extends from Number
*/
public Number getNumber(String attr) {
return (Number) attrs.get(attr);
}
/**
* Paginate.
*
* @param pageNumber the page number
* @param pageSize the page size
* @param select the select part of the sql statement
* @param sqlExceptSelect the sql statement excluded select part
* @param paras the parameters of sql
* @return the Page object
*/
public Page paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
return doPaginate(pageNumber, pageSize, null, select, sqlExceptSelect, paras);
}
/**
* @see #paginate(int, int, String, String, Object...)
*/
public Page paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
return doPaginate(pageNumber, pageSize, null, select, sqlExceptSelect, NULL_PARA_ARRAY);
}
/**
* 指定分页 sql 最外层以是否含有 group by 语句
*
* 举例:
* paginate(1, 10, true, "select *", "from user where id>? group by age", 123);
*
*/
public Page paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
return doPaginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
}
private Page doPaginate(int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
Config config = _getConfig();
Connection conn = null;
try {
conn = config.getConnection();
String totalRowSql = "select count(*) " + config.dialect.replaceOrderBy(sqlExceptSelect);
StringBuilder findSql = new StringBuilder();
findSql.append(select).append(' ').append(sqlExceptSelect);
return doPaginateByFullSql(config, conn, pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);
} catch (Exception e) {
throw new ActiveRecordException(e);
} finally {
config.close(conn);
}
}
private Page doPaginateByFullSql(Config config, Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSql, Object... paras) throws Exception {
if (pageNumber < 1 || pageSize < 1) {
throw new ActiveRecordException("pageNumber and pageSize must more than 0");
}
if (config.dialect.isTakeOverModelPaginate()) {
return config.dialect.takeOverModelPaginate(conn, getUsefulClass(), pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);
}
List result = Db.query(config, conn, totalRowSql, paras);
int size = result.size();
if (isGroupBySql == null) {
isGroupBySql = size > 1;
}
long totalRow;
if (isGroupBySql) {
totalRow = size;
} else {
totalRow = (size > 0) ? ((Number) result.get(0)).longValue() : 0;
}
if (totalRow == 0) {
return new Page(new ArrayList(0), pageNumber, pageSize, 0, 0); // totalRow = 0;
}
int totalPage = (int) (totalRow / pageSize);
if (totalRow % pageSize != 0) {
totalPage++;
}
if (pageNumber > totalPage) {
return new Page(new ArrayList(0), pageNumber, pageSize, totalPage, (int) totalRow);
}
// --------
String sql = config.dialect.forPaginate(pageNumber, pageSize, findSql);
List list = find(conn, sql, paras);
return new Page(list, pageNumber, pageSize, totalPage, (int) totalRow);
}
private Page doPaginateByFullSql(int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) {
Config config = _getConfig();
Connection conn = null;
try {
conn = config.getConnection();
StringBuilder findSqlBuf = new StringBuilder().append(findSql);
return doPaginateByFullSql(config, conn, pageNumber, pageSize, isGroupBySql, totalRowSql, findSqlBuf, paras);
} catch (Exception e) {
throw new ActiveRecordException(e);
} finally {
config.close(conn);
}
}
public Page paginateByFullSql(int pageNumber, int pageSize, String totalRowSql, String findSql, Object... paras) {
return doPaginateByFullSql(pageNumber, pageSize, null, totalRowSql, findSql, paras);
}
public Page paginateByFullSql(int pageNumber, int pageSize, boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) {
return doPaginateByFullSql(pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);
}
/**
* Return attribute Map.
*
* Danger! The update method will ignore the attribute if you change it directly.
* You must use set method to change attribute that update method can handle it.
*/
protected Map _getAttrs() {
return attrs;
}
/**
* Return attribute Set.
*/
public Set> _getAttrsEntrySet() {
return attrs.entrySet();
}
/**
* Save model.
*/
public boolean save() {
filter(FILTER_BY_SAVE);
Config config = _getConfig();
Table table = getTable();
StringBuilder sql = new StringBuilder();
List