【问题标题】:How to generate entity class without create table automatic如何在不自动创建表的情况下生成实体类
【发布时间】:2020-07-15 23:29:54
【问题描述】:

我为我的系统创建了一些报告,该报告由许多表组成。为此,我创建了一个带有 @Entity 注释的 Domain 类并实现了一个 JpaRepository 存储库,我正在使用带有 @Query 的本机查询,如下所示。

我的问题是hibernate正在为每个域类创建一个表,我该如何停止它?

我的域类:

@Entity
@Immutable
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@IdClass(WidgetDailyReportCompositeKey.class)
public class WidgetDailyReportDomain{

    @Id
    @Column(updatable = false, insertable = false)
    private UUID id_construction;

    @Id
    @Column(updatable = false, insertable = false)
    private String name;

    @Id
    @Column(updatable = false, insertable = false)
    private Date dt_cost;

    @Column(updatable = false, insertable = false)
    private Double total;
}

我的仓库:

public interface WidgetRepository extends JpaRepository<WidgetDailyReportDomain, UUID>{

    @Query(value =  "     SELECT ct.id AS id_construction,                                                                                              " +
                    "            ct.name,                                                                                                               " +
                    "            sm.dt_service AS dt_cost,                                                                                              " +
                    "            sum(smi.nu_value * stiv.amount) AS total                                                                               " +
                    "       FROM service_measurement sm                                                                                                 " +
                    " INNER JOIN service_measurement_item smi   ON smi.id_service_measurement = sm.id                                                   " +
                    " INNER JOIN service s                      ON s.id                       = sm.id_service                                           " +
                    " INNER JOIN service_type_item_service stiv ON stiv.id_service            = sm.id_service                                           " +
                    "                                          AND stiv.id_service_type_item = smi.id_service_item                                      " +
                    " INNER JOIN construction ct                ON ct.id                      = s.id_construction                                       " +
                    "      WHERE s.id_construction IN (                                                                                                 " +
                    "                                   select s.id_construction                                                                        " +
                    "                                   from service_measurement sm                                                                     " +
                    "                                   INNER JOIN service_measurement_item smi   ON smi.id_service_measurement = sm.id                 " +
                    "                                   INNER JOIN service s                      ON s.id                       = sm.id_service         " +
                    "                                   INNER JOIN service_type_item_service stiv ON stiv.id_service            = sm.id_service         " +
                    "                                                                            AND stiv.id_service_type_item  = smi.id_service_item   " +
                    "                                   INNER JOIN construction ct                on ct.id                      = s.id_construction     " +
                    "                                   WHERE sm.dt_service BETWEEN :minDate AND :maxDate                                               " +
                    "                                   GROUP BY s.id_construction                                                                      " +
                    "                                   ORDER BY sum(smi.nu_value * stiv.value) DESC                                                    " +
                    "                                   limit :limit                                                                                    " +
                    "       )                                                                                                                           " +
                    "       AND sm.dt_service BETWEEN :minDate AND :maxDate                                                                             " +
                    "  GROUP BY ct.id, sm.dt_service                                                                                                    " +
                    "    HAVING sum(smi.nu_value * stiv.amount) > 0                                                                                     " +
                    "  ORDER BY sm.dt_service;", nativeQuery = true)
    List<WidgetDailyReportDomain> findTopExpensiveConstruction(@Param("minDate") Date minDate, @Param("maxDate") Date maxDate, @Param("limit") int limit);

//....

【问题讨论】:

    标签: java hibernate jpa spring-data-jpa spring-data


    【解决方案1】:

    您的 WidgetDailyReportDomain 实际上是投影。您无需将其标记为@Entity。 您的 @Query 可能属于任何其他真正存在的存储库。

    【讨论】:

    • 如果出于某种原因我没有标记为@Entity,则 JPA 无法映射 UUID 字段并抛出错误:No Dialect mapping for JDBC type: 1111; nested exception is org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111
    • 一种可能的解决方法是使用字符串值在构造函数本身上构建该 UUID 对象
    【解决方案2】:

    您可以删除所有javax.persistence 注释,例如@Column@Id@Entity。这些注释代表了一个表的属性,您似乎不希望它是这样的。

    然后您可以使用 WidgetDailyReportDomain 对象作为 DTO 来作为您的投影,而不是将其附加到 EntityManager: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.dtos

    编辑:另外,不要忘记为该对象构建一个构造函数,以便 Spring JPA 将值加载到对象中(如文档中所述)。 如果你不想构建一个构造函数,也许你可以把它改成一个接口作为你的投影:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces

    【讨论】:

    • 我能够使用 DTO 从数据库中检索数据,但我有一个问题,JPARepository 无法将 id 映射为 UUID。即使我使用@type 进行映射,我仍然会得到No Dialect mapping for JDBC type: 1111; nested exception is org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111。我相信没有@Entity 就不可能使用@type
    【解决方案3】:

    由于您的问题中的 JpaRepository,您似乎正在使用 Spring。

    如果你使用的是 Spring Boot,那么你可以添加

    spring:
      jpa:
        hibernate:
          ddl-auto: none
    

    到您的application.yml 文件,或

    spring.jpa.hibernate.ddl-auto=none
    

    到您的application.properties 文件。

    如果您使用的是persistence.xml 文件,您也可以添加一个属性来禁用它:

    <property name="hibernate.hbm2ddl.auto" value="none"/>
    

    像这样禁用模式表的生成意味着您必须确保它们是通过其他方式创建的,然后您的应用程序才能工作。

    【讨论】:

    • 这就是我想要做的,与 flyway 合作让很多事情变得简单,但所有项目都依赖于此,我无法改变它
    • 那么,您是否希望仅禁用 特定 实体的生成?
    • 没错!我想出了一个不太优雅的解决方案,我将作为答案发布
    【解决方案4】:

    在@Zagarh 回答之后,我对 DTO 进行了一些搜索,我想出了一个不太优雅的解决方案,但这是有效的:

    域类:

    public class WidgetDailyReportDomain{
    
        private UUID id_construction;
        private String name;
        private Date dt_cost;
        private Double total;
    
    }
    

    我必须创建一个自定义结果映射,以便 JPA 能够映射结果,我使用注释 @SqlResultSetMapping。但由于某种原因,她只在一个用@ Entity 注释的类中被识别。为了不变得杂乱无章,我用@ SqlResultSetMapping 创建了一个注释专用的类,因为我有很多映射要做。这个类看起来像这样:

    @MappedSuperclass
    @SqlResultSetMapping(
            name = "widget_daily_mapping",
            classes = {
                    @ConstructorResult(
                            targetClass = WidgetDailyReportDomain.class,
                            columns = {
                                    @ColumnResult(name="id_construction", type = UUID.class),
                                    @ColumnResult(name = "name", type = String.class),
                                    @ColumnResult(name = "dt_cost", type = Date.class),
                                    @ColumnResult(name = "total", type = Double.class)
                            }
    
                    )
            }
    )
    public abstract class ResultSetMappingConfig {
    }
    

    然后我创建了 Jpa Repository 的自定义实现

    public interface WidgetRepositoryCustom {
        List<WidgetDailyReportDomain> findTopExpensiveConstruction(Date minDate, Date maxDate, int limit);
    
    }
    
    
    @Repository
    @Transactional(readOnly = true)
    public class AR_serviceRepositoryImpl implements AR_serviceRepositoryCustom{
    
        @PersistenceContext
        private EntityManager em;
    
        @Override
        public List<AR_serviceDomain> getListOfService(UUID id_construction) {
            Query query = em.createNativeQuery("
              //Native Query Here...
            ", "widget_daily_mapping");// Put the result mapping Here
            query.setParameter(1, id_construction //..Parameters Here);
            return query.getResultList();
        }
    }
    

    Ps:1)如果有人有更好的解决方案,请告诉我。 2) 对不起我的英语,我正在使用谷歌翻译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 2016-02-20
      • 2017-05-13
      • 2011-06-07
      • 1970-01-01
      • 2011-06-17
      • 2020-07-15
      相关资源
      最近更新 更多