REST:为自引用实体扩展CrudRepository会引发异常

问题描述

我有一个问题,经验丰富的用户可能会帮助我。

我有两个班级:Company和Unit:

@Entity(name="Company")
public class Company
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String name;
}

@Entity(name="Unit")
public class Unit
{

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String name;

  @JsonIgnore
  @ManyToOne(optional = false)
  private Company company;

  @JsonIgnore
  @OnetoMany(mappedBy = "parent")
  private List<Unit> subunits = new ArrayList<Unit>();

  @JsonIgnore
  @ManyToOne
  private Unit parent;

}

如您所见,我有几个ManyToOne关系,并且Unit Entity是自引用的。

我还为不想在REST API请求中输出的字段添加了一些@JsonIgnore注释。例如,查询单位时,我不希望返回整个Company对象和所有子单位。但是,我想返回Unit的parentId。另外,当通过REST API添加新的Unit时,我希望客户端能够通过设置“ parentId”:来设置Unit的父Unit。

因此,我认为正确的方法是在单元类添加一个用@Transient注释的字段“ parentId”。这样,它不会保存到数据库,但是在查询时将输出

@Transient
private long parentId;

返回Unit对象时,编写这样的getter就足够了:

public long getParentId()
{
  if (parent != null)
  {
    this.parentId = parent.getId();
  }
  return this.parentId;
}

以及保留新单位时:

Unit parent = unitService.getUnit(newUnit.getParentId); // returns null if there's no Unit with supplied ID
newUnit.setParent = parent;
unitRepository.save(newUnit);

剩下的就是用以下方法扩展CrudRepository:

Iterable<Unit> findByParentId(long parentId);

当我想获取所有单位的子单位(http:// localhost:8080 / company / 1 / units / 2 / subunits)时。

但是,上面的行抛出:

Error creating bean with name 'unitRepository': factorybean threw exception on object creation;
nested exception is java.lang.IllegalArgumentException: Failed to create query for method public
abstract java.lang.Iterable c.a.f.m.unit.UnitRepository.findByParentId(long)! Unable to locate 
Attribute  with the the given name [parentId] on this ManagedType [c.a.f.m.unit.Unit]

对于自引用实体,似乎在创建CrudRepository的方法findByParentId(long id)时,Spring无法区分临时字段parentId和非临时parent.getId()。

我知道可以通过重命名瞬态字段来轻松解决此问题,但是我想知道是否有更优雅的方法解决此问题?也许更有经验的人想出了其他方法来处理这种情况?我觉得我应该做些不同的事情...

谢谢!

解决方法

好的,在发布问题之前,我应该先查阅文档。

Here的描述是Spring如何将方法名转换为实际查询。我需要做的就是添加一个下划线,告诉Spring在哪里拆分属性。 因此,我的方法findByParentId应该命名为findByParent_Id。这样,Spring将忽略parentId属性,而选择parent.id属性。

致谢!