如何将 Hibernate 查询的结果映射到 DTO 对象?

huangapple go评论66阅读模式
英文:

How to map results of a Hibernate Query to a DTO object?

问题

我在我的Java项目中有以下3个Hibernate实体:

CompanyStatus

@Entity(name = "company_status")
@Table(name = "company_status")
public class CompanyStatus implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @JsonProperty
    @Column(name = "company_status_id")
    private Integer companyStatusId;

    @JsonProperty
    @Column(name = "company_status_label")
    private String companyStatusLabel;

}

Employee Status

@Entity(name = "employee_status")
@Table(name = "employee_status")
public class EmployeeStatus implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonProperty
    @Column(name = "employee_status_id")
    private Integer employeeStatusId;

    @JsonProperty
    @Column(name = "employee_status_name")
    private String employeeStatusName;

    // many other fields
}

CompanyStatusEmployeeStatus (连接两个实体的实体-一对一关系)

@Entity(name = "company_status_employee_status")
@Table(name = "company_status_employee_status")
public class CompanyStatusEmployeeStatus implements Serializable {

    // int(20)
    @Id
    @JsonProperty
    @Column(name = "company_status_id")
    private Integer companyStatusId;

    // int(20)
    @JsonProperty
    @Column(name = "employee_status_id")
    private Integer employeeStatusId;
}

我只想在JSON响应中返回必要的字段给前端,所以我创建了一个较小的CompanyStatusDTO对象,其中还嵌套了一个EmployeeStatusDTO列表。

CompanyStatusDTO

public class CompanyStatusDTO {

    @JsonProperty
    private Integer companyStatusId;

    @JsonProperty
    private String companyStatusLabel;

    @JsonProperty
    private List<EmployeeStatusDTO> employeeStatusDTOs;

}

EmployeeStatusDTO

public class EmployeeStatusDTO {

    @JsonProperty
    private Integer employeeStatusId;

    @JsonProperty
    private String employeeStatusName;

}

然而,我对使用Hibernate相对较新 - 是否有一种方法可以创建一个查询,将结果直接映射到我的CompanyStatusDTO对象中?

如果可以,我该如何实现这个需求呢?

英文:

I have the following 3 Hibernate Entities within my Java Project:

CompanyStatus

@Entity(name = &quot;company_status&quot;)
@Table(name = &quot;company_status&quot;)
public class CompanyStatus implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @JsonProperty
    @Column(name = &quot;company_status_id&quot;)
    private Integer companyStatusId;

    @JsonProperty
    @Column(name = &quot;company_status_label&quot;)
    private String companyStatusLabel;

}

Employee Status

@Entity(name = &quot;employee_status&quot;)
@Table(name = &quot;employee_status&quot;)
public class EmployeeStatus implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@JsonProperty
	@Column(name = &quot;employee_status_id&quot;)
	private Integer employeeStatusId;

	@JsonProperty
	@Column(name = &quot;employee_status_name&quot;)
	private String employeeStatusName;

	// many other fields
}

CompanyStatusEmployeeStatus (Entity linking the 2 entities- one to one relationship)

@Entity(name = &quot;company_status_employee_status&quot;)
@Table(name = &quot;company_status_employee_status&quot;)
public class CompanyStatusEmployeeStatus implements Serializable {

    // int(20)
    @Id
    @JsonProperty
    @Column(name = &quot;company_status_id&quot;)
    private Integer companyStatusId;

    // int(20)
    @JsonProperty
    @Column(name = &quot;employee_status_id&quot;)
    private Integer employeeStatusId;
}

I only want to return the necessary fields in my JSON response to the front end , so In order to do so I have created a smaller CompanyStatusDTO object that also has an EmployeeStatusDTO list nested

CompanyStatusDTO

public class CompanyStatusDTO {

    @JsonProperty
    private Integer companyStatusId;

    @JsonProperty
    private String companyStatusLabel;

    @JsonProperty
    private List &lt;EmployeeStatusDTO&gt; employeeStatusDTOs;

}

EmployeeStatusDTO

public class EmployeeStatusDTO {

    @JsonProperty
    private Integer employeeStatusId;

    @JsonProperty
    private String employeeStatusName;

}

However, I am relatively new to using Hibernate - is there a way that I can create a query that will map results directly from my MySQL DB to my CompanyStatusDTOobject?

If so, how can do I this?

答案1

得分: 1

你可以直接使用NativeQuery将查询结果映射到你想要的DTO中(数据类型必须匹配)

String q = "select ... from table"; // 你的SQL查询语句
Query query = getEntityManager().createNativeQuery(q, "EmployeeStatusDTO");
EmployeeStatusDTO data = (EmployeeStatusDTO) query.getSingleResult();
return data;
英文:

you can directly map query result to you desired DTO using NativeQuery (datatype must match)

String q = &quot;select ... from table&quot;; // your sql query
Query query = getEntityManager().createNativeQuery(q, &quot;EmployeeStatusDTO&quot;);
EmployeeStatusDTO data = (EmployeeStatusDTO) query.getSingleResult();
return data;

答案2

得分: 1

这是使用 Blaze-Persistence Entity Views 的完美用例。

我创建了这个库,以便在 JPA 模型和自定义接口或抽象类定义的模型之间实现轻松映射,类似于功能强化版的 Spring Data Projections。核心思想是你可以根据自己的喜好定义目标结构(领域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

如果你稍微调整了 CompanyStatusCompanyStatusEmployeeStatus 实体,并添加以下内容:

public class CompanyStatus implements Serializable {
  //...
  @OneToMany(mappedBy = "companyStatus")
  private Set<CompanyStatusEmployeeStatus> employeeStatuses;
}

public class CompanyStatusEmployeeStatus implements Serializable {
    //...
    @JsonProperty
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "company_status_id", insertable = false, updatable = false)
    private CompanyStatus companyStatus;

    @JsonProperty
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "employee_status_id", insertable = false, updatable = false)
    private EmployeeStatus employeeStatus;
}

你的模型可能会类似如下:

@EntityView(CompanyStatus.class)
public interface CompanyStatusDTO {
    @IdMapping
    Integer getCompanyStatusId();
    String getCompanyStatusLabel();
    @Mapping("employeeStatuses.employeeStatus")
    List<EmployeeStatusDTO> getEmployeeStatusDTOs();
}

@EntityView(EmployeeStatus.class)
public interface EmployeeStatusDTO {
    @IdMapping
    Integer getEmployeeStatusId();
    String getEmployeeStatusName();
}

查询只需要将实体视图应用于查询,最简单的情况是根据 id 进行查询。

CompanyStatusDTO c = entityViewManager.find(entityManager, CompanyStatusDTO.class, id);

Blaze-Persistence Entity Views 还与 Spring Data 集成,使你几乎可以像使用 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

英文:

This is a perfect use case for Blaze-Persistence Entity Views.

I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.

If you adapt the CompanyStatus and CompanyStatusEmployeeStatus entities a bit and add the following:

public class CompanyStatus implements Serializable {
  //...
  @OneToMany(mappedBy = &quot;companyStatus&quot;)
  private Set&lt;CompanyStatusEmployeeStatus&gt; employeeStatuses;
}

public class CompanyStatusEmployeeStatus implements Serializable {
    //...
    @JsonProperty
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = &quot;company_status_id&quot;, insertable = false, updatable = false)
    private CompanyStatus companyStatus;

    @JsonProperty
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = &quot;employee_status_id&quot;, insertable = false, updatable = false)
    private EmployeeStatus employeeStatus;
}

Your model could look like the following:

@EntityView(CompanyStatus.class)
public interface CompanyStatusDTO {
    @IdMapping
    Integer getCompanyStatusId();
    String getCompanyStatusLabel();
    @Mapping(&quot;employeeStatuses.employeeStatus&quot;)
    List&lt;EmployeeStatusDTO&gt; getEmployeeStatusDTOs();
}
@EntityView(EmployeeStatus.class)
public interface EmployeeStatusDTO {
    @IdMapping
    Integer getEmployeeStatusId();
    String getEmployeeStatusName();
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.

CompanyStatusDTO c = entityViewManager.find(entityManager, CompanyStatusDTO.class, id);

The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

答案3

得分: 0

你可以尝试这样做:

public class Dao {

    private SessionFactory sessionFactory;

    public Dao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public <T> T save(final T o) {
        return (T) sessionFactory.getCurrentSession().save(o);
    }

    public void delete(final Object object) {
        sessionFactory.getCurrentSession().delete(object);
    }

    public <T> T get(final Class<T> type, final Long id) {
        return (T) sessionFactory.getCurrentSession().get(type, id);
    }

    public <T> List<T> getAll(final Class<T> type) {
        final Session session = sessionFactory.getCurrentSession();
        final Criteria crit = session.createCriteria(type);
        return crit.list();
    }
    // and so on, you should get the idea
}

然后在服务层中可以这样访问:

private Dao dao;

@Transactional(readOnly = true)
public List<MyEntity> getAll() {
    return dao.getAll(MyEntity.class);
}
英文:

You can try this:

public class Dao{

	private SessionFactory sessionFactory;
    
    public Dao(SessionFactory sessionFactory) {
      this.sessionFactory = sessionFactory;
    }

	public &lt;T&gt; T save(final T o){
      return (T) sessionFactory.getCurrentSession().save(o);
	}


	public void delete(final Object object){
	  sessionFactory.getCurrentSession().delete(object);
	}

	public &lt;T&gt; T get(final Class&lt;T&gt; type, final Long id){
      return (T) sessionFactory.getCurrentSession().get(type, id);
	}

	public &lt;T&gt; List&lt;T&gt; getAll(final Class&lt;T&gt; type) {
	  final Session session = sessionFactory.getCurrentSession();
	  final Criteria crit = session.createCriteria(type);
  return crit.list();
	}
// and so on, you should get the idea

and you can then access like so in the service layer:

    private Dao dao;
   
    @Transactional(readOnly = true)
    public List&lt;MyEntity&gt; getAll() {
      return dao.getAll(MyEntity.class);
    }

huangapple
  • 本文由 发表于 2020年8月19日 23:06:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/63489948.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定