使用 Spring 数据投影获取一对多属性的一部分



我想返回一个包含Parent.id字段的元组并List<Child.id>.


Parent

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Entity
public class Parent implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "id")
private Long parentId;
//we actually use Set and override hashcode&equals
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> children = new ArrayList<>();
public void addChild(Child child) {
child.setParent(this);
children.add(child);
}
public void removeChild(Child child) {
child.setParent(null);
children.remove(child);
}
public Long getParentId() {
return id;
}
public List<Child> getReadOnlyChildren() {
return Collections.unmodifiableList(children);
}
}

Child

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.io.Serializable;
@Entity
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "id")
private Long childId;
@ManyToOne
@JoinColumn(name = "id")
private Parent parent;
public Long getChildId() {
return id;
}
public Parent getParent() {
return parent;
}
/**
* Only for usage in {@link Parent}
*/
void setParent(final Parent parent) {
this.parent = parent;
}
}

春季数据预测:

import java.util.List;
interface IdAndChildrenIds {
Long getParentId();
List<ChildId> getChildren();
}
interface ChildId {
Long getChildId();
}

ParentRepository这就是问题开始的地方:

import org.springframework.data.repository.CrudRepository;
public interface ParentRepository extends CrudRepository<Parent, Long> {
IdAndChildrenIds findIdAndChildrenIdsById(Long id);
}

但这不起作用,因为该属性不符合 JavaBean 标准(gettergetReadOnlyChildren而不是getChildren),所以我配置了ObjectMapper来识别私有字段:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
@Configuration
@EnableWebMvc
public class HibernateConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
ObjectMapper mapper = new Jackson2ObjectMapperBuilder().build();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
converters.add(new MappingJackson2HttpMessageConverter(mapper));
}
}

然后,它仍然不起作用,因为该属性LAZY初始化并且无法在事务外部获取(并且因为我在application.properties中编写了spring.jpa.open-in-view=false,因为这是一种更好的做法)。因此,我必须使用查询指定显式join,并且还必须使用别名,以便 Spring Data 识别属性:

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
public interface ParentRepository extends CrudRepository<Parent, Long> {
@Query("select " +
"    c.parent.parentId   as parentId, " +
"    c.childId as childId" +
"from Child c inner join a.parent p " +
"where p.parentId=:id")
IdAndChildrenIds findIdAndChildrenIdsById(@Param("id") long id);
}

但这又不起作用javax.persistence.NonUniqueResultException: result returns more than one elements因为指定的select给出了元组列表:List<{parentId, childId}>,而我想要一个{parentId, List<childId>}元组。

所以,关于这个答案,我在Long getParentId();中添加了@Value("#{target.parentId}").但这对我的情况没有任何影响。我仍然得到NonUniqueResultException.

然后,我尝试将方法的返回值从IdAndChildrenIds更改为IdAndChildrenIds,只是为了查看错误是否消失,即使该解决方案无济于事。但这也没有用:

无法编写 JSON:找不到类 org.springframework.aop.framework.DefaultAdvisorChainFactory 的序列化程序,也没有发现用于创建 BeanSerializer 的属性

正如我所说,字段可见性已设置为ANY


版本:

- 春季启动 1.5.9.发布  - 弹簧启动启动器数据JPA  - 弹簧启动启动网  - 春哈特亚斯

现在看看这个,奇怪的是我想要父 id 和它的孩子的 id,同时已经知道父 id。

interface ChildRepo{
@org.spring...Query(value = "select id from children where parent_id = :parentId", nativeQuery = true)
List<Long> findIdsByParentId(Long parentId);
}
@lombok.Value
class IdsDto{
Long parentId;
List<Long> childrenIds;
}
public IdsDto createTupleThing(Long parentId){
return new IdsDto(parentId, childRepo.findIdsByParentId(parentId);
}

相关内容

最新更新