在集合中通过精确匹配查找实体
Find entity by exact matching in collection
我有这样的实体:
@Getter
@Setter
@Entity
public class Conversation extends AbstractEntity{
@ElementCollection
@Column(name = "user_id", nullable = false)
@CollectionTable(name = "conversation_user", joinColumns = @JoinColumn(name = "conversation_id", nullable = false))
private List<String> usersIds;
}
是否可以通过用户id的精确匹配找到spring的存储库中的对话实体?例如我有这些实体:
id | user_ids
------------------------------------------
1 | user-a, user-b, user-c
2 | user-a, user-b
3 | user-a, user-c
所以当我想要通过用户 ID user-a
和 user-c
找到对话时,常规 IN 子句如下:
SELECT c FROM Conversation c WHERE c.userIds IN :userIds
会找到 ID 为 1 和 3 的对话,但我想找到完全匹配的对话,所以我的预期结果只是对话 3。
可能的解决方案是在存储库中使用常规 IN 子句,并在服务层中使用下一个过滤器集合,但我更喜欢 returns 直接从数据库中需要实体的解决方案。至少在 JPQL 或本机 sql 中有可能吗?谢谢。
确保 user_ids 列中的用户 ID 按字母顺序排列。因此,例如,当用户 b 进入 ID 为 3 的对话时,'user-a, user-c' 的 user_ids 列变为 'user-a, user-b, user-c'。
接下来请确保当您要根据参与者的完全匹配检索对话时,查询参数中的用户 ID 也按字母顺序排列。
select 可以是
select c from Converation c WHERE c.userIds = :userIds
现在只会找到完全匹配的结果。
您可以在存储库 class 中编写自定义查询,如下所述:
@Repository
public interface YourRepository extends JpaRepository<ConversationModel, Integer> {
@Query(nativeQuery = true, value = "select c from Converation c WHERE c.userId = :userId ORDER BY userId DESC LIMIT 1")
Optional<ConversationModel> findByUserId(@Param("userId") String userId);
}
现在将从数据库层返回完全匹配的 userId。使其可选,并在服务层使用时检查返回值是否为 not null。
要获取多条记录,您必须在查询中使用 IN,如下所述
@Query("select c from Converation c WHERE c.userIds IN :userIds")
List<ConversationModel> findByUserIds(@Param("userIds") List<String> userIds);
希望这能解决您的问题。
使用 HAVING
和 CASE
计算匹配的 userId
并检查是否等于搜索的 userIds
计数。
@Query(value = "SELECT c FROM Conversation c LEFT JOIN c.usersIds cu GROUP BY c "
+ "HAVING SUM(CASE WHEN cu IN (:userIds) THEN 1 ELSE -1 END) = :userIdsCount")
List<Conversation> findByUserIds(@Param("userIds") List<String> userIds,
@Param("userIdsCount") Integer userIdsCount);
我有这样的实体:
@Getter
@Setter
@Entity
public class Conversation extends AbstractEntity{
@ElementCollection
@Column(name = "user_id", nullable = false)
@CollectionTable(name = "conversation_user", joinColumns = @JoinColumn(name = "conversation_id", nullable = false))
private List<String> usersIds;
}
是否可以通过用户id的精确匹配找到spring的存储库中的对话实体?例如我有这些实体:
id | user_ids
------------------------------------------
1 | user-a, user-b, user-c
2 | user-a, user-b
3 | user-a, user-c
所以当我想要通过用户 ID user-a
和 user-c
找到对话时,常规 IN 子句如下:
SELECT c FROM Conversation c WHERE c.userIds IN :userIds
会找到 ID 为 1 和 3 的对话,但我想找到完全匹配的对话,所以我的预期结果只是对话 3。
可能的解决方案是在存储库中使用常规 IN 子句,并在服务层中使用下一个过滤器集合,但我更喜欢 returns 直接从数据库中需要实体的解决方案。至少在 JPQL 或本机 sql 中有可能吗?谢谢。
确保 user_ids 列中的用户 ID 按字母顺序排列。因此,例如,当用户 b 进入 ID 为 3 的对话时,'user-a, user-c' 的 user_ids 列变为 'user-a, user-b, user-c'。
接下来请确保当您要根据参与者的完全匹配检索对话时,查询参数中的用户 ID 也按字母顺序排列。 select 可以是
select c from Converation c WHERE c.userIds = :userIds
现在只会找到完全匹配的结果。
您可以在存储库 class 中编写自定义查询,如下所述:
@Repository
public interface YourRepository extends JpaRepository<ConversationModel, Integer> {
@Query(nativeQuery = true, value = "select c from Converation c WHERE c.userId = :userId ORDER BY userId DESC LIMIT 1")
Optional<ConversationModel> findByUserId(@Param("userId") String userId);
}
现在将从数据库层返回完全匹配的 userId。使其可选,并在服务层使用时检查返回值是否为 not null。
要获取多条记录,您必须在查询中使用 IN,如下所述
@Query("select c from Converation c WHERE c.userIds IN :userIds")
List<ConversationModel> findByUserIds(@Param("userIds") List<String> userIds);
希望这能解决您的问题。
使用 HAVING
和 CASE
计算匹配的 userId
并检查是否等于搜索的 userIds
计数。
@Query(value = "SELECT c FROM Conversation c LEFT JOIN c.usersIds cu GROUP BY c "
+ "HAVING SUM(CASE WHEN cu IN (:userIds) THEN 1 ELSE -1 END) = :userIdsCount")
List<Conversation> findByUserIds(@Param("userIds") List<String> userIds,
@Param("userIdsCount") Integer userIdsCount);