package jef.database.meta; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import jef.accelerator.bean.BeanAccessor; import jef.common.Entry; import jef.database.Field; import jef.database.IQueryableEntity; import jef.database.PojoWrapper; import jef.database.annotation.PartitionFunction; import jef.database.annotation.PartitionKey; import jef.database.annotation.PartitionTable; import jef.database.dialect.DatabaseDialect; import jef.database.dialect.type.AutoIncrementMapping; import jef.database.dialect.type.ColumnMapping; import jef.database.dialect.type.VersionSupportColumn; import jef.database.meta.def.IndexDef; import jef.database.meta.def.UniqueConstraintDef; import com.google.common.collect.Multimap; /** * 表的元模型 * * <h3>什么是元模型</h3> 元模型<meta-model>是一张数据库表的结构在ORM中的描述。<br> * 元模型是一个Java对象,这个对象中存放了数据库表的各种字段、类型等结构定义。 我们可以通过元模型来指定一张表和这张表对应的Java映射类型。 * * <h3>元模型的获得</h3> 一般来说,我们会使用一个类对应数据库中的一张表。比如类 jef.orm.test.Person对应数据库中的 * PERSON表。 我们可以用以下方法来获得这个表的元模型。 * * <pre> * <tt> * ITableMetadata metaModel=MetaHolder.getMeta(jef.orm.test.Person.class) * </tt> * </pre> * * <h3>元模型的种类</h3> 在EF-ORM中,有三种不同的元模型。 {@link #getType()} <li> * {@link EntityType#NATIVE}<br> * 基础映射,一个class对应一张表。<br> * 这个class必须实现jef.database.IQueryableEntity接口。这也是EF-ORM中标准的O-R映射方式<br> * </li> <li>{@link EntityType#TUPLE}<br> * 动态的映射,表没有对应的java类对应,而是用一个类似于Map的结构({@link jef.database.VarObject})来对应。</li> * <li>{@link EntityType#POJO}<br> * 扩展功能,为了支持一些简单的单表CRUD操作,<br> * EF-ORM也可以让一些POJO类映射到数据库表,提供基本的对象操作功能。</li> * * @author Jiyi * @see EntityType#NATIVE * @see EntityType#TUPLE * @see EntityType#POJO */ public interface ITableMetadata { /** * 得到此表对应的java class * * @return 对应的java * class,当metadata为POJO类型时,此处返回PoJoWrapper,为动态表类型时,返回VarObject。 */ Class<? extends IQueryableEntity> getContainerType(); /** * 得到此表对应的模型类。对于基本类型来说,模型类型和容器类型都是一致的。 * * @return 对应的模型类。 */ Class<?> getThisType(); /** * 返回class名称 * * @return class名称 */ String getName(); /** * 返回class名称Simple * * @return class Simple名称 */ String getSimpleName(); /** * 得到该对象绑定的数据源名(重定向后)<br> * ORM允许用户使用Annotation @BindDataSource("db2") 添加在实体类上,指定该实体操作绑定特定的数据源。<br> * 建模时的数据源,在实际运行环境中经过重定向后变为实际部署的数据源名称。<br> * ORM会将对这张表的操作全部在这个数据源上执行。 * * @return 重定向后的数据源名称。 * @see jef.database.annotation.BindDataSource */ String getBindDsName(); /** * 得到schema名称。 ORM允许用户使用Annotation @Table(schema="S1") * 添加在实体类上,指定该实体操作位于特定的schema上。<br> * 建模时的schema,在实际运行环境中经过重定向后变为实际部署的数据源名称。<br> * * @return 重定向后的schema */ String getSchema(); /** * 返回表名 * * @param withSchema * true要求带schema,schema是已经经过了重定向的名称 * @return 返回表名,如果实体绑定了schema,并且withSchema为true,那么返回形如 * <code>schema.table</code>的名称 */ String getTableName(boolean withSchema); /** * 根据名称得到一个Field对象(大小写敏感) * * @param name * 字段名 * @return Field对象(字段元模型) * */ Field getField(String fieldname); /** * 根据数据库列名(小写的)获得field对象 注意传入的列名必须保持小写。 * * @param columnInLowerCase * 数据库列名的小写 * @return FIeld对象(字段元模型) */ Field getFieldByLowerColumn(String columnInLowerCase); /** * 返回所有的元模型字段和类型。这些字段的顺序会进行调整,Clob和Blob将会被放在最后。 这些字段的顺序一旦确定那么就是固定的。 * * 注意当元数据未初始化完成前,不要调用这个方法。 * * @return */ Collection<ColumnMapping> getColumns(); /** * 获取字段的元数据定义 * * @return MappingType,包含了该字段的数据库列名、java字段名、类型等各种信息。 * @see ColumnMapping */ ColumnMapping getColumnDef(Field field); /** * 得到扩展属性的存放表结构 * @return */ TupleMetadata getExtendsTable(); /** * 得到所有的扩展属性字段 * @return */ Collection<ColumnMapping> getExtendedColumns(); /** * 得到指定名称的扩展属性字段 * @param field * @return */ ColumnMapping getExtendedColumnDef(String field); /** * 返回所有自增字段的定义,如果没有则返回空数组 * * @return 所有自增字段的定义 */ AutoIncrementMapping[] getAutoincrementDef(); /** * 返回第一个自增字段的定义,如果没有则返回null * * @return 返回第一个自增字段的定义 */ AutoIncrementMapping getFirstAutoincrementDef(); /** * 需要自动维护数据的列定义(每次更新时自动刷新的列,例如版本或修改时间) * * @return 需要自动维护记录更新的列定义 */ VersionSupportColumn[] getAutoUpdateColumnDef(); /** * 获得用于进行版本控制(防止并发修改冲突)的列定义 * @return the VersionSupportColumn with version usage */ VersionSupportColumn getVersionColumn(); /** * 获取被设置为主键的字段 * * @return */ List<ColumnMapping> getPKFields(); /** * 获取索引的元数据定义 * * @return 索引的定义 */ List<IndexDef> getIndexDefinition(); /** * 得到所有的unique约束 * @return */ List<UniqueConstraintDef> getUniques(); // ///////////////////////引用关联查询相关//////////////////// /** * 按照引用的关系获取所有关联字段 * * @return 关联关系字段 */ Map<Reference, List<AbstractRefField>> getRefFieldsByRef(); /** * 按照名称获得所有关联字段 * * @return 关联关系字段 */ Map<String, jef.database.meta.AbstractRefField> getRefFieldsByName(); // //////////////////////附加功能//////////////////// /** * 根据名称得到一个Field对象(大小写不敏感) * * @param name * @return Field对象 */ ColumnMapping findField(String left); /** * 不考虑表别名的情况返回列名 * * @param field * field * @param profile * 当前数据库方言 * @return 数据库列名 */ String getColumnName(Field field, DatabaseDialect profile, boolean escape); // /////////////////////////分区分库分表相关//////////////////// /** * 获得分表定义 */ PartitionTable getPartition(); /** * 获取当前生效的分区策略 * 注意生效的策略默认等同于Annotation上的策略,但是实际上如果配置了/partition-conf.properties后 * ,生效字段受改配置影响 {@link #partitPolicy} * * @return 当前生效的分区策略 */ @SuppressWarnings("rawtypes") Entry<PartitionKey, PartitionFunction>[] getEffectPartitionKeys(); /** * 获得每个字段上,最小单位的分表函数。 也就是说,其实一个字段上可以对应多个Key,例如有一个Date birthDay 然后KeyA * function=YEAR KeyB function=MONTH 此时在计算枚举时按月计算即可。前一个条件可以忽略。 * * @return 最小单位的分表函数 */ @SuppressWarnings("rawtypes") Multimap<String, PartitionFunction> getMinUnitFuncForEachPartitionKey(); /** * 得到所有数据库字段的名称。(注意,不包含各种映射字段等非数据库字段的名称) * * @return 所有数据库字段的名称 */ Set<String> getAllFieldNames(); /** * 得到实体的类型,有三种值 * * @return 实体的类型 */ EntityType getType(); // /////////////////////////////// 反射与访问 /////////////////////////// /** * 内部使用,得到Bean访问器 * * @return */ BeanAccessor getContainerAccessor(); /** * 创建一个实例 * 在某些情况下个getContainerAccessor().newInstance()不同,因此getContainerAccessor应当仅用于存取字段值,不应用于创建实例 * @return 创建的实例 */ IQueryableEntity newInstance(); // ///////////////////////////// 其他行为 ////////////////////////////// /** * 返回所有的Lob字段 * * @return 所有Lob Field */ Field[] getLobFieldNames(); /** * 将非IQueryableEntity的POJO类型封装为PojoWreapper * * @param p * @return 转换后的PojoWrapper */ PojoWrapper transfer(Object p, boolean isQuery); /** * 由于Entity可以互相继承,引起了metadata也可以继承。 * * @param meta * 要检测的meta * @return 如果当前模型等于meta,或者当前模型继承了meta,返回true */ boolean containsMeta(ITableMetadata meta); ///////////////基于KV表扩展的设计////////////// boolean isCacheable(); boolean isUseOuterJoin(); Map<String,String> getColumnComments(); }