Java 如何使用hibernate查询仅获取具有关联的实体的某些字段?
我有一个实体,它有多个字段,其中一些是关联。 假设该实体具有与以下类似的结构:Java 如何使用hibernate查询仅获取具有关联的实体的某些字段?,java,hibernate,Java,Hibernate,我有一个实体,它有多个字段,其中一些是关联。 假设该实体具有与以下类似的结构: @Entity @Table(name="foos") public class Foo { public Foo() {} @Id private Long id; @Column private String name; @OneToOne(fetch = FetchType.EAGER) @JoinColumn(name = "bar_id") private Bar ba
@Entity
@Table(name="foos")
public class Foo {
public Foo() {}
@Id
private Long id;
@Column
private String name;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "bar_id")
private Bar bar;
@ManyToOne
@JoinColumn(name = "bar1_id")
private Bar1 bar1;
@ManyToOne
@JoinColumn(name = "bar2_id")
private Bar2 bar2;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "foo_id")
private List<Bar3> bar3;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "foo_id")
private List<Bar4> bar4;
//getters and setters
}
@实体
@表(name=“foos”)
公开课Foo{
公共Foo(){}
@身份证
私人长id;
@纵队
私有字符串名称;
@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name=“bar\u id”)
私人酒吧;
@许多酮
@JoinColumn(name=“bar1\u id”)
私人酒吧1酒吧1;
@许多酮
@JoinColumn(name=“bar2\u id”)
私人酒吧2酒吧2;
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,orphan=true)
@JoinColumn(name=“foo\u id”)
私人名单3;
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,orphan=true)
@JoinColumn(name=“foo\u id”)
私人名单4;
//接球手和接球手
}
我的问题是如何使用Hibernate查询仅加载一些字段而不是整个实体?我只想获取id、bar、bar1和bar3,不想获取创建的Foo对象中的其余字段(名称、bar2、bar4)。
我对Hibernate非常陌生,因此任何建议都将受到欢迎。最简单的方法是创建一个存储库,根据选择的标准获取对象,然后如果使用Spring数据,则仅从对象列表中提取所需的字段: 仅对于hibernate,它应该如下所示:
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
Foo foo = entityManager.find(Foo.class,id);
entityManager.getTransaction().commit();
或使用自定义SQL查询,仅适用于所选字段:
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
Query query = entityManager.createQuery("SELECT e FROM Foo e");
List<Foo> workerList = query.getResultList();
EntityManager EntityManager=EntityManager工厂。createEntityManager();
entityManager.getTransaction().begin();
Query Query=entityManager.createQuery(“从fooE中选择e”);
List workerList=query.getResultList();
在以下帮助下,我解决了这个问题。我创建了一个新的实体FooShort,具有相同的表名“foos”,并且只包含Foo所需的字段
@Entity
@Table(name="foos")
public class FooShort {
public FooShort() {}
@Id
private Long id;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "bar_id")
private Bar bar;
@ManyToOne
@JoinColumn(name = "bar1_id")
private Bar1 bar1;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "foo_id")
private List<Bar3> bar3;
//getters and setters
}
@实体
@表(name=“foos”)
公开课{
公共FooShort(){}
@身份证
私人长id;
@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name=“bar\u id”)
私人酒吧;
@许多酮
@JoinColumn(name=“bar1\u id”)
私人酒吧1酒吧1;
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,orphan=true)
@JoinColumn(name=“foo\u id”)
私人名单3;
//接球手和接球手
}
Hibernate 5,Spring 5
您有几个选项,但最简单的选项是使用所需的列/字段创建一个简单的@Query,请参见我的一个项目中的示例代码
首先也是最重要的一点是,您不需要创建带有子集字段的DTO,我将显示这两个字段和混合版本的选项
选项一:带有列/字段子集的DTO对象
DTO存储库代码:
@Query( "SELECT new com.your.package.name.customers.CompanyDTOIdName(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC" )
List<CompanyDTOIdName> compDtoNameWhereEnabledTrue();
@Query( "SELECT new com.your.package.name.customers.Company(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC"
)
List<Company> compNameWhereEnabledTrue();
@Query( "SELECT new com.csfactorynw2.site.customers.Company(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC"
)
List<CompanyDTOIdNameInterface> compNameWhereEnabledTrue();
休眠SQL执行代码:
SELECT
new com.your.package.name.customers.CompanyDTOIdName(c.id, c.name)
FROM
Company c
WHERE
c.enabled = 1
ORDER BY
c.name ASC
select
company0_.companyId as col_0_0_,
company0_.name as col_1_0_
from
ome_company company0_
where
company0_.enabled=1
order by
company0_.name ASC
SELECT
new com.your.package.name.customers.Company(c.id, c.name)
FROM
Company c
WHERE
c.enabled = 1
ORDER BY
c.name ASC
select
company0_.companyId as col_0_0_,
company0_.name as col_1_0_
from
ome_company company0_
where
company0_.enabled=1
order by
company0_.name ASC
主要的缺点是,对于每一个不同的列组合,都需要一个单独的DTO对象
选项二:使用原始@Entity 第二个选项更简单,可用于任何列子集,如下所示: 存储库代码:
@Query( "SELECT new com.your.package.name.customers.CompanyDTOIdName(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC" )
List<CompanyDTOIdName> compDtoNameWhereEnabledTrue();
@Query( "SELECT new com.your.package.name.customers.Company(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC"
)
List<Company> compNameWhereEnabledTrue();
@Query( "SELECT new com.csfactorynw2.site.customers.Company(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC"
)
List<CompanyDTOIdNameInterface> compNameWhereEnabledTrue();
休眠SQL执行代码:
SELECT
new com.your.package.name.customers.CompanyDTOIdName(c.id, c.name)
FROM
Company c
WHERE
c.enabled = 1
ORDER BY
c.name ASC
select
company0_.companyId as col_0_0_,
company0_.name as col_1_0_
from
ome_company company0_
where
company0_.enabled=1
order by
company0_.name ASC
SELECT
new com.your.package.name.customers.Company(c.id, c.name)
FROM
Company c
WHERE
c.enabled = 1
ORDER BY
c.name ASC
select
company0_.companyId as col_0_0_,
company0_.name as col_1_0_
from
ome_company company0_
where
company0_.enabled=1
order by
company0_.name ASC
注意:我相信您可以看到这种方法的问题。仅加载指定的列/字段。如果试图访问未启动的字段,则会出现异常
使用接口的混合版本(两个世界中最好的) 使用必需的访问器字段创建接口
public interface CompanyDTOIdNameInterface {
public Long getId();
public String getName();
}
在@Entity对象上实现接口
public class Company implements Serializable,
CompanyDTOIdNameInterface
{ /* omitted code */ }
存储库代码:
@Query( "SELECT new com.your.package.name.customers.CompanyDTOIdName(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC" )
List<CompanyDTOIdName> compDtoNameWhereEnabledTrue();
@Query( "SELECT new com.your.package.name.customers.Company(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC"
)
List<Company> compNameWhereEnabledTrue();
@Query( "SELECT new com.csfactorynw2.site.customers.Company(c.id, c.name) " +
"FROM Company c " +
"WHERE c.enabled = 1 " +
"ORDER BY c.name ASC"
)
List<CompanyDTOIdNameInterface> compNameWhereEnabledTrue();
@Query(“选择新com.csfactorynw2.site.customers.Company(c.id,c.name)”+
“来自c公司”+
“其中c.enabled=1”+
“按c.name ASC订购”
)
列出compNameWhereEnabledTrue();
就这么简单。祝你好运:)谢谢你的回答。但我认为上面的查询将从数据库中获取foo对象的所有字段。我想要的是只从db将上述四个字段加载到foo对象中,即,生成的foo对象不应从db中获取bar2和bar4的任何值。修改HQL查询应该可以做到这一点,即“从FooE中选择e.name”。如果您需要HQL方面的帮助,这里有一个教程。如果您愿意,Hibernate还允许使用本机SQL查询。我试过了,对于作为表一部分的列,这将很好地工作。但是对于关联,必须编写大量连接,这可能会使查询变得复杂。在林克的帮助下,我解决了这个问题。我创建了一个新的实体FooShort,具有相同的表名“foos”,并且只包含Foo所需的字段。