package com.malk.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

/**
 * JPA [错误抛出与拦截详见CatchException, 多数据源配置参考DataSourceConfig]
 * -
 * 1. 关键字语法: save find, exists, count [单表操作 - 若数据库列和对象属性字段一致, 直接使用 jpa 自带查询匹配不到启动报错]
 * 2. 自定义查询: @Query, 通过 nativeQuery 区分 jpql 和 sql 语法 [简单查询]
 * 3. 表关联关系: @OneToMany, @ManyToOne, @ManyToMany, @OneToOne [耦合关联]
 * 4. Specification: Predicate 与 CriteriaBuilder 组合 [谓词, 需要依赖于实体]
 * 5. QueryDSL: 基于ORM框架以及SQL之上的一个通用的查询框架, 分页, 关联查询原生支持 [查询框架] (通过查询关联, 而不是如 @OneToMany 等建立表关联)
 * 6. DSL: 项目在 compile 会执行 apt-maven-plugin 插件, 将 @Entity 注解类, 添加 Q 前缀, 存放到 target 下 generated-source 目录
 * 7. 配置: 扫描基础路径, 涉及子项目也能注册到, 避免启动报错. 子项目 Boot 配置 @SpringBootApplication(scanBasePackages = {"com.mcli"})
 * 8. 查询: 使用native，查询列不匹配实体属性，会报错The column name xxx is not valid，返回Map可解决 (Map是Jpa的TupleBackedMap, 通过try取值)
 * 9. 单数据源切换: 在dao与entity均添加mutual作为公共模块, 单数据源下服务于JpaConfiguration, 若是多数据源与PrimaryConfig一起作为主数据源配置
 * 10 主子项目, 在单数据源情况下, 扫描全部. [需要注意的是, 在多数据源下同名dao是可以通过指定数据源使用, 此时若开启单数据源启动报错, 会扫描全部]
 */
@ConditionalOnProperty(name = "spel.multiSource", havingValue = "false")
@Configuration
// 单数据源, 扫描子项目与主项目primary [子项目可以访问到主项目primary]
@EnableJpaRepositories(basePackages = {"com.malk.*.repository.dao", "com.malk.repository.dao.primary"})
@EntityScan(basePackages = {"com.malk.*.repository.entity", "com.malk.repository.entity.primary"})
public class JpaConfiguration {

    @Bean
    PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
        return new PersistenceExceptionTranslationPostProcessor();
    }
}
