有没有办法减少与 CriteriaQuery(在 JPA 2.0 中)相关的样板代码量?

发布于 2024-09-05 09:06:02 字数 1393 浏览 9 评论 0原文

我喜欢 CriteriaQuery 带来的类型安全JPA 2.0,但它也带来了一些样板代码。例如,假设我有一个名为 NamedEntity 的实体,它只有一个 id 和一个名为“name”的字符串字段(假设它的唯一约束设置为 true)。 NamedEntityManager 可能如下所示:

public class NamedEntityManager
{
    //inject using your framework
    EntityManager entityManager;

    //retrieve all existing entities of type NamedEntity from DB
    public Iterable<NamedEntity> queryAll()
    {
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
        return entityManager.createQuery(query).getResultList();
    }

    //retrieve a single entity of type NamedEntity from DB using specified name
    public NamedEntity queryByName(String name)
    {
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
        Root<NamedEntity> root = query.from(NamedEntity.class);
        query = query.where(root.<NamedEntity>get("name").in(name));

        //skipped the try/catch block for the sake of brevity
        return entityManager.createQuery(query).getSingleResult();
    }
}

有没有办法压缩代码以避免将相同的代码行复制/粘贴到每个查询方法中?也许以某种方式重用 CriteriaQuery 对象?

I love the type safety CriteriaQuery brings ing JPA 2.0 but it also brings a bit of boiler-plate code. For example, let say I have an entity called NamedEntity, which simply has an id and a String field called "name" (assume it has the unique constraint set to true). Here's what the NamedEntityManager might look like:

public class NamedEntityManager
{
    //inject using your framework
    EntityManager entityManager;

    //retrieve all existing entities of type NamedEntity from DB
    public Iterable<NamedEntity> queryAll()
    {
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
        return entityManager.createQuery(query).getResultList();
    }

    //retrieve a single entity of type NamedEntity from DB using specified name
    public NamedEntity queryByName(String name)
    {
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
        Root<NamedEntity> root = query.from(NamedEntity.class);
        query = query.where(root.<NamedEntity>get("name").in(name));

        //skipped the try/catch block for the sake of brevity
        return entityManager.createQuery(query).getSingleResult();
    }
}

Is there a way to condense the code in order to avoid copying/pasting the same lines of code into each query method? Perhaps somehow reuse the CriteriaQuery object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

攒一口袋星星 2024-09-12 09:06:02

我正在寻找类似的东西,你可以看看 Querydsl (LGPL 许可)可以有 JPA 作为后端。

我仍在阅读它,但从他们的例子来看,它看起来很干净。

HQLQuery q = new HibernateQuery(session);
QCat cat = new QCat("cat"); // query type
List<Cat> cats = q.from(cat).where(cat.name.between("A", "B")).list(cat);

I was looking for something like that, you could take a look at Querydsl (LGPL licensed) which can have JPA as backend.

Im still reading into it, but from their examples, it looks pretty clean.

HQLQuery q = new HibernateQuery(session);
QCat cat = new QCat("cat"); // query type
List<Cat> cats = q.from(cat).where(cat.name.between("A", "B")).list(cat);
玻璃人 2024-09-12 09:06:02

在 JPA 2.1 中,很可能混合 JPQL 和 Criterias。通过这种方法,您可以使用 JPQL 定义基本查询,然后使用 Criteria API 动态添加小部分。

我认为 API 会不会那么冗长,因为您只需要使用它的一小部分。

In JPA 2.1, it will most probably be possible to mix JPQL and Criterias. With such an approach you could define a base query with JPQL and then use the Criteria API to dynamically add small parts.

I figure the API will be less verbose then, since you only need to use small parts of it.

泅人 2024-09-12 09:06:02

看来没有办法减少代码量了。我想必须牺牲一些东西才能获得类型安全。

It seems there's no way to reduce the amount of code. I guess something had to be sacrificed to gain type safety.

浅沫记忆 2024-09-12 09:06:02

这篇文章已经过时了,但我想添加我最近为简单查询构建的内容

    public static class Jpa2Whatsoever {

    private final EntityManager em;

    public class Jpa2WhatsoeverProgress<T> {

        private CriteriaQuery<T> cq;
        private List<Predicate> predicates = new ArrayList<>();
        private Root<T> root;

        public Jpa2WhatsoeverProgress(Class<T> type) {
            this.cq = em.getCriteriaBuilder().createQuery(type);
            this.root = cq.from(type);

        }

        public Jpa2WhatsoeverProgress<T> where(String attributeName, Object value) {

            Predicate equal = em.getCriteriaBuilder().equal(root.get(attributeName), value);

            predicates.add(equal);
            return this;
        }

        public List<T> getResultList() {
            Predicate[] predicatesArray = new Predicate[predicates.size()];
            TypedQuery<T> typedQuery = em.createQuery(cq.select(root).where(predicates.toArray(predicatesArray)));

            List<T> resultList = typedQuery.getResultList();

            return Collections.unmodifiableList(resultList);
        }

    }

    public Jpa2Whatsoever(EntityManager entityManager) {
        this.em = entityManager;
    }

    public <T> Jpa2WhatsoeverProgress<T> select(Class<T> type) {
        return new Jpa2WhatsoeverProgress<T>(type);
    }
}

你可以像这样使用它

List<MyEntity> matchingEntities = new Jpa2Whatsoever(entityManager).select(MyEntity.class).where("id", id).where("due", new Date()).getResultList();

最后我停止了这个。主要是因为我看到我只有两个查询,我必须扩展 DSL 才能将所需的查询特征放入其中,例如

  • 大于、小于
  • 元模型支持
  • QueryBuilder.currentDate() 等。

此外,我发现总是调用 where 很丑陋,而它实际上对应于更 SQLly 的 and。不管怎样,如果有人对一个非常简单的查询 API 感兴趣,它仍然值得一试。

顺便说一句:忘记名字吧,这只是一个原型,仅此而已。

Way outdated, this post, but I want to add what I recently built for simple queries

    public static class Jpa2Whatsoever {

    private final EntityManager em;

    public class Jpa2WhatsoeverProgress<T> {

        private CriteriaQuery<T> cq;
        private List<Predicate> predicates = new ArrayList<>();
        private Root<T> root;

        public Jpa2WhatsoeverProgress(Class<T> type) {
            this.cq = em.getCriteriaBuilder().createQuery(type);
            this.root = cq.from(type);

        }

        public Jpa2WhatsoeverProgress<T> where(String attributeName, Object value) {

            Predicate equal = em.getCriteriaBuilder().equal(root.get(attributeName), value);

            predicates.add(equal);
            return this;
        }

        public List<T> getResultList() {
            Predicate[] predicatesArray = new Predicate[predicates.size()];
            TypedQuery<T> typedQuery = em.createQuery(cq.select(root).where(predicates.toArray(predicatesArray)));

            List<T> resultList = typedQuery.getResultList();

            return Collections.unmodifiableList(resultList);
        }

    }

    public Jpa2Whatsoever(EntityManager entityManager) {
        this.em = entityManager;
    }

    public <T> Jpa2WhatsoeverProgress<T> select(Class<T> type) {
        return new Jpa2WhatsoeverProgress<T>(type);
    }
}

You can use it like this

List<MyEntity> matchingEntities = new Jpa2Whatsoever(entityManager).select(MyEntity.class).where("id", id).where("due", new Date()).getResultList();

In the end I stopped this. Mainly because I saw that I had only two queries and I would have to extend the DSL to get the required query characteristics into it, such as

  • greater than, less than
  • Metamodel support
  • QueryBuilder.currentDate() and alike.

Further, I find it ugly to always call where while it actually corresponds to a more SQLly and. Anyway, if someone is interested in a very simple query API, it is still worth a try.

BTW: Forget about the names, this was a prototype, nothing more.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文