package org.easyframe.enterprise.spring;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.persistence.NonUniqueResultException;
import jef.common.wrapper.Page;
import jef.database.DbClient;
import jef.database.IQueryableEntity;
import jef.database.NamedQueryConfig;
import jef.database.NativeQuery;
import jef.database.RecordHolder;
import jef.database.RecordsHolder;
import jef.database.Session;
import jef.database.meta.ITableMetadata;
import jef.database.query.Query;
import jef.database.wrapper.ResultIterator;
/**
* 通用Dao接口(非泛型),和泛型的{@link GenericDao}相对
*
* 将业务逻辑上移后,dao层淡化的结果。这个commonDao提供了几乎所有实体的creatia api操作
* @author jiyi
*
*@see GenericDao
*/
public interface CommonDao{
/**
* 插入记录(不带级联)
* @param entity 要插入的记录
* @return 插入后的记录
*/
<T> T insert(T entity);
/**
* 插入记录(带级联的插入记录)
* @param entity
* @return
*/
<T> T insertCascade(T entity);
/**
* 在记录已经存在的情况下更新,否则插入记录
*
* @param entity 要持久化的记录
*/
void persist(Object entity);
/**
* 在记录已经存在的情况下更新,否则插入记录
*
* @param entity
* @return
*/
<T> T merge(T entity);
/**
* 删除记录(不带级联)
*
* @param entity 待删除对象(模板).
* <ul>
* <li>如果对象是{@link IQueryableEntity}设置了Query条件,按query条件查询。 否则——</li>
* <li>如果设置了主键值,按主键查询,否则——</li>
* <li>按所有设置过值的字段作为条件查询。</li></ul>
*/
int remove(Object entity);
/**
* 删除记录(带级联)
* @param entity
* <ul>
* <li>如果对象是{@link IQueryableEntity}设置了Query条件,按query条件查询。 否则——</li>
* <li>如果设置了主键值,按主键查询,否则——</li>
* <li>按所有设置过值的字段作为条件查询。</li></ul>
*/
int removeCascade(Object entity);
/**
* 根据模板的对象删除记录。
*
* @param entity 作为删除条件的对象(模板)
* @param properties 作为删除条件的字段名。当不指定properties时,首先检查entity当中是否设置了主键,如果有主键按主键删除,否则按所有非空字段作为匹配条件。
* @return
*/
<T> int removeByExample(T entity,String... properties);
/**
* 删除全部记录
* @param meta 元数据描述
*/
void removeAll(ITableMetadata meta);
/**
* 批量删除指定属性值的记录
* @param meta 元数据描述
* @param propertyName 属性名称
* @param values 属性值列表
*/
void removeByProperty(ITableMetadata meta, String propertyName, List<?> values);
/**
* 查询列表
*
* @param data 查询请求。
* <ul>
* <li>如果设置了Query条件,按query条件查询。 否则——</li>
* <li>如果设置了主键值,按主键查询,否则——</li>
* <li>按所有设置过值的字段作为条件查询。</li></ul>
* @return 结果
*/
<T> List<T> find(T data);
/**
* 根据主键查询
* @param type 类
* @param id 主键
* @return 查询结果
* @since 1.10
*/
<T> T load(Class<T> type,Serializable... id);
/**
* 查询数据
* @param data 查询请求
* @return 结果
* @since 1.10
*/
<T extends IQueryableEntity> List<T> find(Query<T> data);
/**
* 查找对象并且返回遍历器
* @param obj 查询请求
* <ul>
* <li>如果设置了Query条件,按query条件查询。 否则——</li>
* <li>如果设置了主键值,按主键查询,否则——</li>
* <li>按所有设置过值的字段作为条件查询。</li></ul>
* @return 结果遍历器
*/
<T> ResultIterator<T> iterate(T obj);
/**
* 根据样例查找
* @param entity 查询条件
* @param property 作为查询条件的字段名。当不指定properties时,首先检查entity当中是否设置了主键,如果有主键按主键删除,否则按所有非空字段作为匹配条件。
* @return 查询结果
*/
<T> List<T> findByExample(T entity,String... properties);
/**
* 查询并分页
* @param data 查询请求
* @param start 起始记录,offset。从0开始。
* @param limit 限制记录条数。如每页10条传入10。
* @return
*/
<T> Page<T> findAndPage(T data,int start,int limit);
/**
* 查询一条记录,如果结果不唯一则抛出异常
*
* @param data
* @param unique
* 要求查询结果是否唯一。为true时,查询结果不唯一将抛出异常。为false时,查询结果不唯一仅取第一条。
* @throws NonUniqueResultException
* 结果不唯一
* @return 查询结果
*/
<T> T load(T data);
/**
* 根据查询查询一条记录
* @param entity
* @param unique true表示结果必须唯一,false则允许结果不唯一仅获取第一条记录
* @return 查询结果
* @throws NonUniqueResultException
* 结果不唯一
*/
public <T> T load(T entity, boolean unique);
/**
* 更新记录(不带级联)
* @param entity 要更新的对象
* @return 影响的记录条数
*/
<T> int update(T entity);
/**
* 更新记录(带级联)
* @param entity
* @return
*/
<T> int updateCascade(T entity);
/**
* 更新记录
* @param entity 要更新的对象
* @param property where字段值
* @return 影响的记录条数
*/
<T> int updateByProperty(T entity,String... property);
/**
* 带有附加条件的记录更新
* @param entity 实体仅作WHERE条件使用
* @param setValues 要更新哪些字段的Map
* @param property 哪些字段用作Where条件
* @return
*/
<T> int update(T entity,Map<String,Object> setValues,String... property);
/**
* 执行命名查询
* {@linkplain NamedQueryConfig 什么是命名查询}
* @param nqName 命名查询名称
* @param type 返回类型
* @param params 查询参数
* @return 查询结果
*/
<T> List<T> findByNq(String nqName, Class<T> type,Map<String, Object> params);
/**
* 执行命名查询
* {@linkplain NamedQueryConfig 什么是命名查询}
* @param nqName 命名查询名称
* @param meta 返回类型
* @param params 查询参数
* @return 查询结果
*/
<T> List<T> findByNq(String nqName, ITableMetadata meta,Map<String, Object> params);
/**
* 使用命名查询查找并分页
* {@linkplain NamedQueryConfig 什么是命名查询}
* @param nqName 命名查询名称
* @param type 返回类型
* @param params 查询参数
* @param start 开始记录数,从0开始
* @param limit 限制结果条数
* @return 查询结果
*/
<T> Page<T> findAndPageByNq(String nqName, Class<T> type,Map<String, Object> params, int start,int limit);
/**
* 使用命名查询查找并分页
* {@linkplain NamedQueryConfig 什么是命名查询}
* @param nqName 命名查询名称
* @param meta 返回类型
* @param params 查询参数
* @param start 开始记录数,从0开始
* @param limit 限制结果条数
* @return 查询结果
*/
<T> Page<T> findAndPageByNq(String nqName, ITableMetadata meta,Map<String, Object> params, int start,int limit);
/**
* 使用命名查询执行(更新/创建/删除)等操作
* {@linkplain NamedQueryConfig 什么是命名查询}
* @param nqName 命名查询名称
* @param params sql参数
* @return 查询结果
*/
int executeNq(String nqName,Map<String,Object> params);
/**
* 执行指定的SQL(更新/创建/删除)等操作
* @param sql SQL语句,可使用 {@linkplain NativeQuery 增强的SQL (参见什么是E-SQL条目)}。
* @param param
* @return 查询结果
*/
int executeQuery(String sql,Map<String,Object> param);
/**
* 根据指定的SQL查找
* @param sql SQL语句,可使用 {@linkplain NativeQuery 增强的SQL (参见什么是E-SQL条目)}。
* <pre><code>
* String sql="select * from table where 1=1 and id=:id<int> and name like :name<$string>";
* Map<String, Object> params = new HashMap<String,Object>();
* params.put(id,123);
* params.put(name,"Join");
* session.findByQuery(sql,ResultClass.class, params); //根据SQL语句查询,返回类型为ResultClass。
* <code></pre>
* @param retutnType 返回类型
* @param params 绑定变量参数
* @return 查询结果
*/
<T> List<T> findByQuery(String sql,Class<T> retutnType, Map<String, Object> params);
/**
* 查找对象并且返回遍历器
* @param sql SQL语句,可使用 {@linkplain NativeQuery 增强的SQL (参见什么是E-SQL条目)}。
* @param returnType
* @param params 参数
* @return
*/
<T> ResultIterator<T> iterateByQuery(String sql,Class<T> returnType,Map<String,Object> params);
/**
* 查找对象并且返回遍历器
* @param sql SQL语句,可使用 {@linkplain NativeQuery 增强的SQL (参见什么是E-SQL条目)}。
* @param returnType 返回类型的元数据模型
* @param params 参数
* @return
*/
<T> ResultIterator<T> iterateByQuery(String sql, ITableMetadata returnType, Map<String, Object> params);
/**
* 根据指定的SQL查找
* @param sql SQL语句,可使用 {@linkplain NativeQuery 增强的SQL (参见什么是E-SQL条目)}。
* @param retutnType
* @param params
* @return 查询结果
*/
<T> List<T> findByQuery(String sql,ITableMetadata retutnType, Map<String, Object> params);
/**
* 根据指定的SQL查找并分页
* @param sql SQL语句,可使用 {@linkplain NativeQuery 增强的SQL (参见什么是E-SQL条目)}。
* @param retutnType 返回结果类型
* @param params 绑定变量参数
* @param start 起始记录行,第一条记录从0开始。
* @param limit 每页记录数
* @return 查询结果
*/
<T> Page<T> findAndPageByQuery(String sql,Class<T> retutnType, Map<String, Object> params,int start,int limit);
/**
* 根据指定的SQL查找并分页
* @param sql SQL语句,可使用 {@linkplain NativeQuery 增强的SQL (参见什么是E-SQL条目)}。
* @param retutnType 返回结果类型
* @param params 绑定变量参数
* @param start 起始记录行,第一条记录从0开始。
* @param limit 每页记录数
* @return
*/
<T> Page<T> findAndPageByQuery(String sql,ITableMetadata retutnType, Map<String, Object> params,int start,int limit);
/**
* 根据主键的值加载一条记录
* @param entityClass
* @param primaryKey
* @return 查询结果
*/
<T> T loadByPrimaryKey(Class<T> entityClass, Serializable primaryKey);
/**
* 根据主键的值批量加载记录 (不支持复合主键)
* @param entityClass 实体类
* @param values 多个主键值
*/
<T> List<T> loadByPrimaryKeys(Class<T> entityClass, List<? extends Serializable> values);
/**
* 根据主键的值加载一条记录
* @param meta 数据库表的元模型. {@linkplain ITableMetadata 什么是元模型}
* @param id
* @return 查询结果
*/
<T> T loadByPrimaryKey(ITableMetadata meta, Object id);
/**
* 根据某个指定字段进行查找
* @param meta
* @param propertyName
* @param value
* @return
*/
<T> List<T> findByField(Class<T> meta, String propertyName, Object value);
/**
* 根据某个指定属性的值查找
* @param meta 数据库表的元模型. {@linkplain ITableMetadata 什么是元模型}
* @param propertyName
* @param value
* @return 查询结果
*/
List<?> findByField(ITableMetadata meta, String propertyName, Object value);
/**
* 根据指定的字段批量查找记录
* @param meta
* @param propertyName
* @param value, 要查找的记录的字段值(多个)
* @return
*/
List<?> findByField(ITableMetadata meta, String propertyName, List<? extends Serializable> value);
/**
* 使用已知的属性查找一个结果
* @param meta 数据库表的元模型. {@linkplain ITableMetadata 什么是元模型}
* @param field 字段名
* @param unique
* true要求查询结果必须唯一。false允许结果不唯一,但仅取第一条。
* @param id
* @return 查询结果
* @throws NonUniqueResultException
* 结果不唯一
*/
<T> T loadByField(ITableMetadata meta,String field,Serializable id,boolean unique);
/**
* 根据指定的字段查找单条记录。如果结果不唯一抛出NonUniqueResultException
* @param field 条件字段
* @param value 条件值
* @return 查询结果
* @throws NonUniqueResultException
* 结果不唯一
*/
<T extends IQueryableEntity> T loadByField(jef.database.Field field, Object value);
/**
* 根据指定的字段查找单条记录。
* @param field 条件字段
* @param value 条件值
* @param unique 是否要求结果唯一。为true时如果结果不唯一会抛出NonUniqueResultException
* @return 查询结果
* @throws NonUniqueResultException
* 结果不唯一
*/
<T extends IQueryableEntity> T loadByField(jef.database.Field field, Object value, boolean unique);
/**
* 根据指定的字段值读取单个记录
* @param meta 数据库表的元模型. {@linkplain ITableMetadata 什么是元模型}
* @param unique
* true要求查询结果必须唯一。false允许结果不唯一,但仅取第一条。
* @param field
* @param id
* @return 查询结果
* @throws NonUniqueResultException
* 结果不唯一
*/
<T> T loadByField(Class<T> meta,String field,Serializable key,boolean unique);
/**
* 根据指定的字段值删除记录
* @param meta 数据库表的元模型. {@linkplain ITableMetadata 什么是元模型}
* @param field
* @param value
* @return 影响记录行数
*/
<T> int removeByField(Class<T> meta,String field,Serializable value);
/**
* 根据指定的字段值删除记录
* @param meta 数据库表的元模型. {@linkplain ITableMetadata 什么是元模型}
* @param field
* @param value
* @return 影响记录行数
*/
int removeByField(ITableMetadata meta,String field,Serializable value);
/**
* 得到当前的数据库操作Session
*/
Session getSession();
/**
* 得到当前无事务的操作Session,可以在其上执行各种DDL。访问Database MetaData等。<br>
* 因为DDL和DML混合执行的话,会造成事务被误提交。使用 getNoTransactionSession()方法得到的Session上执行DDL时,不会引起当前事务的变化。
* @see DbClient
* @see DbClient#getMetaData(String)
*/
DbClient getNoTransactionSession();
/**
* 批量插入
*
* @param entities 要写入的对象列表
* @return 影响记录行数
*/
<T> int batchInsert(List<T> entities);
/**
* 批量插入,使用extreme模式插入
* @param entities 要写入的对象列表
* @return 影响记录行数
*/
<T> int extremeInsert(List<T> entities);
/**
* 批量插入
* @param entities 要写入的对象列表
* @param doGroup 是否对每条记录重新分组。{@linkplain jef.database.Batch#isGroupForPartitionTable 什么是重新分组}
* @return 影响记录行数
*/
<T> int batchInsert(List<T> entities,Boolean doGroup);
/**
* 批量删除(按主键)
*
* @param entities 要删除的对象列表
* @return 影响记录行数
*/
<T> int batchDelete(List<T> entities);
/**
* 批量删除(按主键)
* @param entities 要删除的对象列表
* @param doGroup 是否对每条记录重新分组。{@linkplain jef.database.Batch#isGroupForPartitionTable 什么是重新分组}
* @return 影响记录行数
*/
<T> int batchDelete(List<T> entities,Boolean doGroup);
/**
* 批量(按主键)更新
*
* @param entities 要写入的对象列表
* @return 影响记录行数
*/
<T> int batchUpdate(List<T> entities);
/**
* 批量(按主键)更新
* @param entities 要写入的对象列表
* @param doGroup 是否对每条记录重新分组。{@linkplain jef.database.Batch#isGroupForPartitionTable 什么是重新分组}
* @return 影响记录行数
*/
<T> int batchUpdate(List<T> entities,Boolean doGroup);
/**
* 返回一个可以更新操作的结果数据集合 实质对用JDBC中ResultSet的updateRow,deleteRow,insertRow等方法, <br>
* 该操作模型需要持有ResultSet对象,因此注意使用完毕后要close()方法关闭结果集<br>
*
* RecordsHolder可以对选择出来结果集进行更新、删除、新增三种操作,操作完成后调用commit方法<br>
*
* @param obj
* 查询请求
* @return RecordsHolder对象,这是一个可供操作的数据库结果集句柄。注意使用完后一定要关闭。
* @throws SQLException
* 如果数据库操作错误,抛出。
* @see RecordsHolder
*/
<T extends IQueryableEntity> RecordsHolder<T> selectForUpdate(Query<T> query);
/**
* 返回一个可以更新操作的结果数据{@link RecordHolder}<br>
* 用户可以在这个RecordHolder上直接更新数据库中的数据,包括插入记录和删除记录<br>
*
* <h3>实现原理</h3> RecordHolder对象,是JDBC ResultSet的封装<br>
* 实质对用JDBC中ResultSet的updateRow,deleteRow,insertRow等方法,<br>
* 该操作模型需要持有ResultSet对象,因此注意使用完毕后要close()方法关闭结果集。 <h3>注意事项</h3>
* RecordHolder对象需要手动关闭。如果不关闭将造成数据库游标泄露。 <h3>使用示例</h3>
*
*
* @param obj
* 查询对象
* @return 查询结果被放在RecordHolder对象中,用户可以直接在查询结果上修改数据。最后调用
* {@link RecordHolder#commit}方法提交到数据库。
* @throws SQLException
* 如果数据库操作错误,抛出。
* @see RecordHolder
*/
<T extends IQueryableEntity> RecordHolder<T> loadForUpdate(Query<T> obj);
/**
* 返回一个可以更新操作的结果数据{@link RecordHolder}<br>
* 用户可以在这个RecordHolder上直接更新数据库中的数据,包括插入记录和删除记录<br>
*
* <h3>实现原理</h3> RecordHolder对象,是JDBC ResultSet的封装<br>
* 实质对用JDBC中ResultSet的updateRow,deleteRow,insertRow等方法,<br>
* 该操作模型需要持有ResultSet对象,因此注意使用完毕后要close()方法关闭结果集。 <h3>注意事项</h3>
* RecordHolder对象需要手动关闭。如果不关闭将造成数据库游标泄露。 <h3>使用示例</h3>
*
*
* @param obj
* 查询对象
* @return 查询结果被放在RecordHolder对象中,用户可以直接在查询结果上修改数据。最后调用
* {@link RecordHolder#commit}方法提交到数据库。
* @throws SQLException
* 如果数据库操作错误,抛出。
* @see RecordHolder
*/
<T extends IQueryableEntity> RecordHolder<T> loadForUpdate(T query);
}