问题描述
我有两个班级: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”:
因此,我认为正确的方法是在单元类中添加另一个用@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属性。
致谢!