通过JPA规范

时间:2016-02-04 07:59:43

标签: hibernate jpa spring-data-jpa

我有useruser_related_user个表以及User JPA实体, 与自己有很多关系。

@Entity @Table(name = "user")
public class User implements Serializable {

  @Id @GeneratedValue
  private Long id;

  @ManyToMany(cascade = {CascadeType.ALL})
  @JoinTable(
    name = "user_related_user",
    joinColumns = {
      @JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
    },
    inverseJoinColumns = {
      @JoinColumn(name = "related_user_id", referencedColumnName = "id", nullable = false)
    }
  )
  public List<User> relatedUsers;
}

我想通过JPA规范从User#relatedUsers获取User#id。 所以我必须联合这个用户的相关用户&#34;和#34;更多用户&#34;动态。

在SQL中,需要以下查询。

SELECT u.id FROM user u WHERE u.id IN (
  SELECT uru.related_user_id
  FROM user_related_user uru
  WHERE uru.user_id = ?
)

但我不知道如何使用JPA规范。 有谁知道更好的解决方案?

目前的解决方法是

@Repository
public interface UserRepository 
  extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {

  @Query("select ru.id from User u join u.relatedUsers ru where u.id = ?1")
  List<Long> findRelatedUserIds(Long id);
}

@Service @Transactional(readOnly = true)
public class UserService {

  @Autowired
  UserRepository repository;

  public List<Users> getSelectableUsers(Long id, /* and args */) {

    List<Long> currentRelatedUserIds = repository.findRelatedUserIds(id);

    Specification<User> spec = (root, query, cb) -> {

      return cb.or(
        root.get(User_.id).in(currentRelatedUserIds),
        /* generate some more predicates dynamically */
      );
    }

    return repository.findAll(spec);
  }
}

2 个答案:

答案 0 :(得分:1)

如果我理解正确,您希望能够让相关用户找到用户。

我的输入数据是

insert into user values(1);
insert into user values(2);
insert into user values(3);
insert into user values(4);
insert into user values(5);
insert into user values(6);
insert into user values(7);
insert into user values(8);
insert into user values(9);
insert into user values(10);

insert into user_related_user values(1,10);
insert into user_related_user values(1,9);
insert into user_related_user values(1,8);
insert into user_related_user values(2,7);
insert into user_related_user values(2,6);
insert into user_related_user values(2,5);

我的存储库是

@Repository
public interface UserRepository 
  extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {

  @Query("select ru.id from User u join u.relatedUsers ru where u.id = ?1")
  List<Long> findRelatedUserIds(Long id);

  List<User> findDistinctByRelatedUsersIdIn(List<Long> ids);
}

我的测试是

List<User> selectableUsers = userRepository.findDistinctByRelatedUsersIdIn(Arrays.asList(new Long[]{10l,9l,8l,7l,6l,5l}));
        assertEquals(2, selectableUsers.size());

希望这有帮助。

答案 1 :(得分:0)

最后我通过使用SubQuery来解决这个问题。

public List<Users> getSelectableUsers(Long id, /* and args */) {

  Specification<User> spec = (root, query, cb) -> {

    query.distinct(true);

    Subquery<User> sq = query.subquery(User.class);
    Root<User> sqRoot = sq.from(User.class);
    sq.select(
      sqRoot.join(User_.relatedUsers)
    ).where(
      cb.equal(sqRoot.get(User_.id), id)
    );

    return cb.or(
      root.in(sq),
      // some more dynamic condition
    );
  }

  return repository.findAll(spec);
}