有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Hibernate标准。继承构造

我有超级班

@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditEntityListener.class)
public abstract class AuditEntity {
    public static final String ID = "id";
    public static final String ORGANIZATION = "organization";
    public static final String CREATED_BY = "createdBy";
    public static final String MODIFIED_BY = "modifiedBy";
    public static final String CREATED_DATETIME = "createdDatetime";
    public static final String MODIFIED_DATETIME = "modifiedDatetime";
    public static final String STATE = "state";

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "organization_id")
    protected Organization organization;

    @Column(name = "created_datetime")
    protected Instant createdDatetime;

    @Column(name = "modified_datetime")
    protected Instant modifiedDatetime;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "created_by")
    protected User createdBy;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "modified_by")
    protected User modifiedBy;

    @Enumerated(EnumType.STRING)
    @Column(name = "state")
    protected State state;

}

实体扩展了超类

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(of = {"id"}, callSuper = false)
@Entity
@Table(name = "inventory_request")
public class InventoryRequest extends AuditEntity {

    public static final String NAME = "name";
    public static final String REQUESTER = "requester";
    public static final String SOURCE = "source";
    public static final String EVENT = "event";
    public static final String TRANSFER = "transfers";
    public static final String ASSIGNMENT = "assignment";
    public static final String INVENTORY_REQUEST_STATUS = "status";
    public static final String NOTES = "notes";

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "inventory_request_id")
    private UUID id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "email", nullable = false)
    private String email;

    @ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
    @JoinColumn(name = "requester_id")
    private User requester;

    @ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
    @JoinColumn(name = "source_id")
    @ApiModelProperty(hidden = true)
    private User source;

    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false, length = 24)
    private InventoryRequestStatus status;

    @Column(name = "carrier")
    private String carrier;

    @Column(name = "tracking_number")
    private String trackingNumber;

    @Column(name = "note", length = 1024)
    private String note;

    @JsonManagedReference
    @ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
    @JoinColumn(name = "event_id")
    private Event event;

    @Column(name = "number", nullable = false)
    private Long number;

    @Column(name = "tracking_enabled", nullable = false)
    private Boolean trackingEnabled;

    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy = Transfer.INVENTORY_REQUEST)
    private Set<Transfer> transfers;

    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy = InventoryRequestAssignment.INVENTORY_REQUEST)
    private Set<InventoryRequestAssignment> assignment;

    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy = InventoryRequestNote.INVENTORY_REQUEST)
    private Set<InventoryRequestNote> notes;
}

这是我想用criteria api选择的一个类

@NoArgsConstructor
@Getter
@Setter
public class InventoryRequestDTO extends InventoryRequest {

    public InventoryRequestDTO(InventoryRequest inventoryRequest,
                               Long completeSetsQuantity,
                               Long specificProductQuantity) {
        super(inventoryRequest.getId(),
                inventoryRequest.getName(),
                inventoryRequest.getEmail(),
                inventoryRequest.getRequester(),
                inventoryRequest.getSource(),
                inventoryRequest.getStatus(),
                inventoryRequest.getCarrier(),
                inventoryRequest.getTrackingNumber(),
                inventoryRequest.getNote(),
                inventoryRequest.getEvent(),
                inventoryRequest.getNumber(),
                inventoryRequest.getTrackingEnabled(),
                inventoryRequest.getTransfers(),
                inventoryRequest.getAssignment(),
                inventoryRequest.getNotes());
        this.completeSetsQuantity = completeSetsQuantity;
        this.specificProductQuantity = specificProductQuantity;
    }

    private Long completeSetsQuantity;
    private Long specificProductQuantity;
}

这就是我尝试过的方法

   @Transactional
    public Page<? extends InventoryRequest> getInventoryRequestPage(InventoryRequestSearchParams searchParams, Pageable pageable) {
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<InventoryRequest> query = builder.createQuery(InventoryRequest.class);
        Root<InventoryRequest> root = query.from(InventoryRequest.class);
        Join<InventoryRequest, InventoryRequestAssignment> assignmentJoin = root.join(InventoryRequest.ASSIGNMENT, JoinType.LEFT);
        Expression<Long> specificProductQuantity = builder.count(builder.selectCase()
                .when(assignmentJoin.get(InventoryRequestAssignment.CATALOG).isNotNull(), 1)
                .otherwise(0));
        Expression<Long> completeSetsQuantity = builder.count(builder.selectCase()
                .when(assignmentJoin.get(InventoryRequestAssignment.CATALOG).isNull(), 1)
                .otherwise(0));

        Predicate predicate = InventoryRequestSpecificationComposer.builder()
                .searchParams(searchParams)
                .build()
                .compose()
                .toPredicate(root, query, builder);

        query.select(
                builder.construct(InventoryRequestDTO.class,
                        root,
                        completeSetsQuantity,
                        specificProductQuantity))
                .where(predicate);

        Query q = entityManager.createQuery(query);

        int totalRows = q.getResultList().size();
        q.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
        q.setMaxResults(pageable.getPageSize());
        return new PageImpl<>(q.getResultList(), pageable, totalRows);
    }

但我有个例外

org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias2,role=com.connectsx.core.model.entity.InventoryRequest.createdBy,tableName=users,tableAlias=user2_,origin=inventory_request inventoryr0_,columns={inventoryr0_.created_by ,className=com.connectsx.core.model.entity.User}}] 

我还有审计实体的规范生成器,它获取organizationcreated_bymodified_by属性。但是如果我选择InventoryRequest.class,它工作得很好,而使用DTO则失败


共 (1) 个答案

  1. # 1 楼答案

    如果传递整个实体,那么使用构造函数表达式是没有意义的。您也可以获取实体并调用结果列表对象上的构造函数。然而,如果你真的想提高性能,这是一个完美的Blaze-Persistence Entity Views用例

    我创建了这个库,以便在JPA模型和自定义接口或抽象类定义的模型之间进行简单的映射,比如Spring数据在类固醇上的投影。其思想是,您可以按照自己喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(getter)映射到实体模型。因为属性名被用作默认映射,所以您基本上不需要显式映射,因为80%的用例都需要DTO作为实体模型的子集

    用例的示例模型可能如下所示:

    @EntityView(InventoryRequest.class)
    public interface InventoryRequestDTO {
        @IdMapping
        UUID getId();
        String getName();
        String getEmail();
        UserDTO getRequester();
        UserDTO getSource();
        InventoryRequestStatus getStatus();
        String getCarrier();
        String getTrackingNumber();
        String getNote();
        EventIdView getEvent();
        Long getNumber();
        Boolean getTrackingEnabled();
        @Mapping(fetch = FetchStrategy.MULTISET)
        Set<TransferDTO> getTransfers();
        @Mapping(fetch = FetchStrategy.MULTISET)
        Set<InventoryRequestAssignmentDTO> getAssignment();
        @Mapping(fetch = FetchStrategy.MULTISET)
        Set<InventoryRequestNoteDTO> getNotes();
        @Mapping("COUNT(*) FILTER (WHERE assignment.catalog IS NULL)")
        Long getCompleteSetsQuantity();
        @Mapping("COUNT(*) FILTER (WHERE assignment.catalog IS NOT NULL)")
        Long getSpecificProductQuantity();
    }
    
    @EntityView(User.class)
    public interface UserDTO {
        @IdMapping
        UUID getId();
        // Other fields you need
    }
    
    @EntityView(Transfer.class)
    public interface TransferDTO {
        @IdMapping
        UUID getId();
        // Other fields you need
    }
    
    @EntityView(InventoryRequestAssignment.class)
    public interface InventoryRequestAssignmentDTO {
        @IdMapping
        UUID getId();
        // Other fields you need
    }
    
    @EntityView(InventoryRequestNote.class)
    public interface InventoryRequestNoteDTO {
        @IdMapping
        UUID getId();
        // Other fields you need
    }
    

    查询是将实体视图应用于查询的问题,最简单的就是按id进行查询

    InventoryRequestDTO dto = entityViewManager.find(entityManager, InventoryRequestDTO.class, id);

    Spring数据集成允许您像使用Spring数据投影一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features即拥有一个类似于以下内容的存储库

    @Repository
    public interface InventoryRepository {
        Page<InventoryRequestDTO> findAll(Specification specification, Pageable pageable);
    }
    

    它只会得到你告诉它的东西。享受吧