Find entity by exact matching in collection

牧云@^-^@ 提交于 2021-01-27 05:01:08

问题


I have entity like this:

@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;
}

Is possible to find conversation entity by spring's repository by exact matching of user ids? For instance I have these entities:

 id | user_ids
------------------------------------------
 1  | user-a, user-b, user-c
 2  | user-a, user-b
 3  | user-a, user-c

So when I will be want found conversation by user ids user-a and user-c regular IN clause like this:

SELECT c FROM Conversation c WHERE c.userIds IN :userIds

will found conversations with id 1 and 3, but I want find exact match, so my expected result is only conversation 3.

Possible solution is use regular IN clause in repository, and next filter collection in service layer but I prefer solution which returns required entity directly from database. Is it possible in JPQL or native sql at least? Thank you.


回答1:


Use HAVING with CASE to count matched userId and check equal with searched userIds count.

@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);



回答2:


Ensure that the user ids in the user_ids column are kept alphabetically ordered. So for example when user b enters the conversation with id 3, the user_ids column that was 'user-a, user-c' becomes 'user-a, user-b, user-c'.

Next make sure that when you want to retrieve a converation based on an exact match of participants, the user ids in the argument to your query is alphabetically ordered as well. The select can then be

select c from Converation c WHERE c.userIds = :userIds

Now only exact matches will be found.




回答3:


You can write a custom query in your Repository class as mentioned below:

@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);

}

Now exact matching userId will be getting returned from the database layer. Make it optional and check if the returned value is not null while using in the service layer.

For fetching multiple records you'll have to use IN in the Query as mentioned below

 @Query("select c from Converation c WHERE c.userIds IN :userIds")
    List<ConversationModel> findByUserIds(@Param("userIds") List<String> userIds);

Hopefully, this will resolve your issue.



来源:https://stackoverflow.com/questions/62488165/find-entity-by-exact-matching-in-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!