【问题标题】:Create a Dynamic Query in Spring在 Spring 中创建动态查询
【发布时间】:2015-08-16 20:05:33
【问题描述】:

我使用标准 JPA 实现已经有一段时间了,并且在创建由算法生成的动态查询以在数据库中搜索用户时没有遇到任何问题。但是,我们正在转向 Spring Framework(不幸的是,旧版本 - 3.2),我根本不知道如何在 Spring 中创建动态查询。

使用javax.persistance.EntityManager,我可以调用createQuery 并给它一个字符串以供使用。但是,我发现在 Spring 中,我只能使用类似以下代码的代码,在注释中定义查询。

@Repository
@SuppressWarnings("unused")
public interface PersonRepository extends JpaRepository<Person, Long>, CrudRepository<Person, Long> {

    @Override
    List<Person> findAll(Sort sort);

    @Override
    List<Person> findAll();

    @Query("SELECT p FROM Person p ORDER BY p.lname ASC, p.fname ASC, p.mname ASC")
    List<Person> findAllSort();

    @Query("SELECT p FROM Person p WHERE UPPER(p.userName) = UPPER(?1)")
    Person findPersonByUsername(String username);


}

这是我可以给你的最简单的动态查询示例,我想为 Spring 复制:

public List<Person> getPersons(List<Long> perIds) {
    List<Person> persons;
    String whereClause = "";
    for (int i = 0; i < perIds.size(); i++) {
        if (i != 0)
            whereClause += " OR ";
        whereClause += "p.perId = '" + perIds.get(i) + "'";
    }
    persons = em.createQuery("SELECT p FROM Person p WHERE " + whereClause).getResultList();
    return persons;
}

也许一个更好的问题是问这是否可能,或者我是否应该只使用实体管理器保留我的实现。话虽如此,有人推荐我将我的代码从使用 EntityManager 更改为使用 Spring Framework 吗?

【问题讨论】:

  • 你能澄清一下吗?也许提供一个你想要做什么的例子?当您说“从实体管理器更改为 Spring 框架”时……这对我来说没有任何意义,它们不是相互排斥的概念,甚至不一定相关。
  • 我真正希望找到的是 Spring 可能有自己的“createQuery”方法实现,这样我就可以执行 JPA 或幼稚查询。但是,如果 Spring 不提供 createQuery 函数的自己的实现,我可以保留我当前的实现。

标签: spring spring-mvc jpa spring-data


【解决方案1】:

请考虑下面的例子。可能你正在寻找这样的东西。虽然你的问题不是很直截了当你想要什么。使用标准或规范你可以实现许多很酷的事情。

@Service 

Optional<Person> findByEmail(String email);


@NoRepositoryBean
public interface PersonRepositoryCustom {
    Optional<Person> findByEmail(String email);
}

@Repository
public class PersonRepositoryImpl extends QuerydslRepositorySupport implements PersonRepositoryCustom {
    public PersonRepositoryImpl() {
        super(Person.class);
    }

    @Override
    public Optional<Person> findByEmail(String email) {
        JPAQuery<Person> query = getQuerydsl()
                .createQuery()
                .from(QPerson.person)
                .where(QPerson.person.email.equalsIgnoreCase(email))
                .select(QPerson.person);
        return query.fetch().stream().findFirst();
    }
}

【讨论】:

    【解决方案2】:

    为什么不改用IN 查询条件?

    春天应该允许你这样做:

    @Query( "SELECT p FROM Person p WHERE p.perId in :ids" )
    findPersonsInIdList(@Param("ids") List<Long> perIds);
    

    【讨论】:

    • 您的解决方案适用于该特定查询,但是,我有其他查询从更复杂的算法生成,这些查询根本无法使用诸如此类的方法解决。不过感谢您的提示!
    【解决方案3】:

    Spring允许您使用@Repository,但不会强制您这样做。 Spring 甚至提供了一个很好的 JPA 接口,将低级关注点(数据源定义和事务管理)与高级关注点(DAO,带有声明性事务)分开。

    Spring Framework Reference Manual 中有一个chapter 关于 JPA。您还应该阅读前面章节中有关事务管理的部分。

    【讨论】:

    • 感谢更新;我有同样的想法,但我认为 spring 可能是自己实现的较低级别的操作。在这种情况下,我将坚持使用我当前的实现。再次感谢!
    【解决方案4】:

    我不知道我们能否满足您的要求。 但我有一个替代你的方法。

    public List<Person> getPersons(List<Long> perIds) {
        return em.createQuery(
            "SELECT p FROM Person p WHERE p.perId = " 
            + org.springframework.util.StringUtils.collectionToDelimitedString(perIds, " OR p.perId = ", "'", "'")
        ).getResultList();
    }
    

    【讨论】:

    • 这个方法很方便!我会在未来记住这一点,但这并不是我想要的。据我了解,我的意图在 Spring 中可能是不可能的。不过感谢您的提示!我会浏览那个图书馆,看看它还有什么。
    猜你喜欢
    • 2020-02-12
    • 1970-01-01
    • 2014-02-24
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    相关资源
    最近更新 更多