Spring JPA findByDomainClass生成错误的where子句

时间:2016-01-02 17:47:03

标签: java spring hibernate spring-mvc jpa

我在使用Spring JPA时遇到了问题。我用谷歌搜索和研究半天,但没有结果。让我告诉你我的代码。我编写了一个实体,它在数据库中引用了另一个带有外键的域类,但实体的连接列不是主键'id'。这两个实体如下:

@Entity
@Table(name = "tb_user")
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String username;
    ... getters and setters ...
}

@Entity
@Table(name = "tb_timebank")
public class TimebankEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @ManyToOne
    @JoinColumn(name = "username")
    private UserEntity user;
    ... getters and setters ...
}

我使用spring JPA CrudRepository来执行自定义查询:

@Repository
public interface UserRepository extends CrudRepository<UserEntity, Long> {
    public UserEntity findByUsername(String username);
}

@Repository
public interface TimebankRepository extends CrudRepository<TimebankEntity, Long> {
    public TimebankEntity findByUser(UserEntity user);
}

这很简单。但是,当我在服务中执行业务逻辑时,出现了问题。

@Service
public class TimebankService {
    @Autowired
    TimebankRepository timebankRepository;

    @Autowired
    UserRepository userRepository;
    public TimebankDto getTimebank(String username) {
        UserEntity userEntity = userRepository.findByUsername(username);
        TimebankEntity timebankEntity = timebankRepository
                .findByUser(userEntity);
        return new TimebankDto(timebankEntity.getUser().getUsername(),
                timebankEntity.getLeaveType().getCode(),
                timebankEntity.getTotalHours(),
                timebankEntity.getAvailableHours());
    }
}

我使用用户名'Tom'运行上面的代码,我可以获得我的数据库中存在的正确userEntity。但是findByUser(userEntity)返回null结果。 hibernate生成的sql和消息是以下输出:

Hibernate: select userentity0_.id as id1_2_, userentity0_.introduction as introduc2_2_, userentity0_.password as password3_2_, userentity0_.username as username4_2_ from tb_user userentity0_ where userentity0_.username=?
Hibernate: select timebanken0_.id as id1_1_, timebanken0_.available_hours as availabl2_1_, timebanken0_.leave_type as leave_ty4_1_, timebanken0_.total_hours as total_ho3_1_, timebanken0_.username as username5_1_ from tb_timebank timebanken0_ left outer join tb_user userentity1_ on timebanken0_.username=userentity1_.id where userentity1_.id=?
o.h.engine.jdbc.spi.SqlExceptionHelper:SQL Warning Code: 1292, SQLState: 22007
o.h.engine.jdbc.spi.SqlExceptionHelper:Truncated incorrect DOUBLE value: 'Tom'

似乎'Tom'已分配给字段'id',因此它返回null结果,但为什么会发生这种情况呢?我的代码出了什么问题?我检查了春季jpa参考,但我没有找到答案。请给我一些建议并提前感谢!

1 个答案:

答案 0 :(得分:1)

首先,你正在寻找错误的地方。你有一个JPA映射问题,你的JPA实现是Hibernate。因此,您应该在JPA / Hibernate文档中查找问题,而不是在Spring文档中。

您告诉JPA / Hibernate,TimebankEntity与UserEntity之间存在关联:

@ManyToOne
@JoinColumn(name = "username")
private UserEntity user;

这意味着表username中有一列tb_timebank,用于引用tb_user表的一行。但是你不能在任何地方说出这一列引用的tb_user表的哪一列。

唯一引用另一个表的行的最自然的方法是什么?当然是主键。所以,当然,如果您没有指定任何内容,那就是JPA将使用的内容。怎么改变?

让我们阅读API documentation of JoinColumn

  

referencedColumnName

     

public abstract java.lang.String referencedColumnName

     

(可选)此外键列引用的列的名称。

     

[...]

     

默认值(仅在使用单个连接列时适用):与引用表的主键列相同的名称。

因此,默认情况下,引用的列名称是引用表的主键列的名称,即tb_user.id

要引用另一列,您需要为此属性指定一个值:

@JoinColumn(name = "username", referencedColumnName = "username")

也就是说,您最好使用默认值:如果两个用户具有相同的名称,并且不会强制您更新{{},那么效率会更高,不会导致问题。 1}}当用户更改其名称时