জেপিএ 2-তে, একটি ক্রেটারিয়াকিয়ারি ব্যবহার করে কীভাবে ফলাফল গণনা করা যায়


114

আমি জেপিএ 2 এর পরিবর্তে নতুন এবং এটি ক্রেটারিয়াবিল্ডার / ক্রেটারিয়াকিয়ার এপিআই:

CriteriaQuery javadoc

CriteriaQuery জাভা ইই 6 টি টিউটোরিয়ালে

আমি কোনও ক্রিটারিয়াকোয়ারির ফলাফলগুলি আসলে পুনরুদ্ধার না করে গণনা করতে চাই। এটি কি সম্ভব, আমি এই জাতীয় কোনও পদ্ধতি খুঁজে পাইনি, এটি করার একমাত্র উপায় হ'ল:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();

CriteriaQuery<MyEntity> cq = cb
        .createQuery(MyEntityclass);

// initialize predicates here

return entityManager.createQuery(cq).getResultList().size();

এবং এটি এটি করার উপযুক্ত উপায় হতে পারে না ...

একটি সমাধান আছে কি?


যদি কেউ নীচে উত্তরগুলিতে সহায়তা করতে বা অন্তর্ভুক্ত করতে পারে তবে এটি খুব কার্যকর হবে। জেপিএ মানদণ্ড এপিআই ব্যবহার করে নিম্নলিখিত গণনা ক্যোয়ারী কীভাবে অর্জন করবেন? my_table থেকে গণনা (স্বতন্ত্র কল 1, কল 2, কল 3) নির্বাচন করুন;
ভবেশ

নিচে কিন্তু এর পরিবর্তে qb.count ব্যবহার qb.distinctCount @Bhavesh উত্তর খুঁজছেন
Tonino

উত্তর:


220

টাইপের একটি ক্যোয়ারী MyEntityফিরতে চলেছে MyEntity। আপনি একটি জন্য একটি প্রশ্ন চান Long

CriteriaBuilder qb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = qb.createQuery(Long.class);
cq.select(qb.count(cq.from(MyEntity.class)));
cq.where(/*your stuff*/);
return entityManager.createQuery(cq).getSingleResult();

স্পষ্টতই আপনি উদাহরণটিতে যা এড়িয়ে গেছেন না কেন এমন কোনও বিধিনিষেধ এবং গ্রুপিং ইত্যাদির সাহায্যে আপনার অভিব্যক্তিটি তৈরি করতে চাইবেন।


3
ধন্যবাদ, আমি এটাই নিজেকে আবিষ্কার করেছি। তবে এর অর্থ যে ফলাফলগুলির সংখ্যা এবং আমি জানি যে সত্যের ফলাফল এসকিউএল এর সাথে সাদৃশ্যযুক্ত, সেগুলির জন্য জিজ্ঞাসা করার জন্য আমি একই ক্যোয়ারী উদাহরণটি ব্যবহার করতে পারি না, তবে যা এই এপিআইটিকে আরও অনেক বেশি ওওপি-জাতীয় করে তুলবে। ভাল, কমপক্ষে আমি পূর্বাভাসের কিছু পুনরায় ব্যবহার করতে পারি, আমার ধারণা।
সান প্যাট্রিক ফ্লয়েড

6
@ বারেট এটি যদি একটি বৃহত গণনা হয় তবে আপনি সম্ভবত কতগুলি আছে তা খুঁজে বার করার জন্য মেমোরিতে কয়েকশ বা হাজার হাজার সত্ত্বার একটি তালিকা লোড করতে চান না!
এফিড

@ বারেট এটি অনেকটা পৃষ্ঠা-র ক্ষেত্রে ব্যবহার করা হয়। সুতরাং মোট সংখ্যা এবং আসল সারিগুলির একটি উপসেট প্রয়োজন।
gkephorus

2
আপনি মনে রাখবেন যে qb.countমাধ্যমে সম্পন্ন করা হয় Root<MyEntity>(আপনার ক্যোয়ারী Root<MyEntity>myEntity = cq.from (MyEntity.class)) এবং এই ঘন ঘন আপনার স্বাভাবিক নির্বাচন কোড আগে থেকেই এবং আপনি ভুলে গেলে একটি স্ব যোগদান দিয়ে শেষ।
gkephorus

2
অবজেক্টগুলি পুনরুদ্ধারের জন্য একই মানদণ্ড এবং গোষ্ঠীতে আপনার এলিয়াস ব্যবহারের প্রয়োজন হতে পারে সেই গণনাগুলির পুনরায় ব্যবহার করতে উদাহরণস্বরূপ ফোরাম.হিবারনেট.অর্গ / ভিউটোপিক.এফপি? পিপি 24241515#p2471522 দেখুন ।
পুল

31

আমি cb.createQuery () (ফলাফলের ধরণের পরামিতি ছাড়াই) ব্যবহার করে এটি বাছাই করেছি:

public class Blah() {

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery query = criteriaBuilder.createQuery();
    Root<Entity> root;
    Predicate whereClause;
    EntityManager entityManager;
    Class<Entity> domainClass;

    ... Methods to create where clause ...

    public Blah(EntityManager entityManager, Class<Entity> domainClass) {
        this.entityManager = entityManager;
        this.domainClass = domainClass;
        criteriaBuilder = entityManager.getCriteriaBuilder();
        query = criteriaBuilder.createQuery();
        whereClause = criteriaBuilder.equal(criteriaBuilder.literal(1), 1);
        root = query.from(domainClass);
    }

    public CriteriaQuery<Entity> getQuery() {
        query.select(root);
        query.where(whereClause);
        return query;
    }

    public CriteriaQuery<Long> getQueryForCount() {
        query.select(criteriaBuilder.count(root));
        query.where(whereClause);
        return query;
    }

    public List<Entity> list() {
        TypedQuery<Entity> q = this.entityManager.createQuery(this.getQuery());
        return q.getResultList();
    }

    public Long count() {
        TypedQuery<Long> q = this.entityManager.createQuery(this.getQueryForCount());
        return q.getSingleResult();
    }
}

আশা করি এটা সাহায্য করবে :)


23
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
cq.select(cb.count(cq.from(MyEntity.class)));

return em.createQuery(cq).getSingleResult();

12

অন্যের উত্তর যেমন সঠিক, তবে খুব সহজ, সুতরাং পরিপূর্ণতার জন্য আমি SELECT COUNTএকটি পরিশীলিত জেপিএ মানদণ্ডের কোয়েরিতে (একাধিক যোগদান, ফেচ, শর্ত সহ) সম্পাদনের জন্য কোড স্নিপেটের নীচে উপস্থাপন করছি ।

এটি এই উত্তরটি সামান্য পরিবর্তিত হয়েছে ।

public <T> long count(final CriteriaBuilder cb, final CriteriaQuery<T> selectQuery,
        Root<T> root) {
    CriteriaQuery<Long> query = createCountQuery(cb, selectQuery, root);
    return this.entityManager.createQuery(query).getSingleResult();
}

private <T> CriteriaQuery<Long> createCountQuery(final CriteriaBuilder cb,
        final CriteriaQuery<T> criteria, final Root<T> root) {

    final CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    final Root<T> countRoot = countQuery.from(criteria.getResultType());

    doJoins(root.getJoins(), countRoot);
    doJoinsOnFetches(root.getFetches(), countRoot);

    countQuery.select(cb.count(countRoot));
    countQuery.where(criteria.getRestriction());

    countRoot.alias(root.getAlias());

    return countQuery.distinct(criteria.isDistinct());
}

@SuppressWarnings("unchecked")
private void doJoinsOnFetches(Set<? extends Fetch<?, ?>> joins, Root<?> root) {
    doJoins((Set<? extends Join<?, ?>>) joins, root);
}

private void doJoins(Set<? extends Join<?, ?>> joins, Root<?> root) {
    for (Join<?, ?> join : joins) {
        Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType());
        joined.alias(join.getAlias());
        doJoins(join.getJoins(), joined);
    }
}

private void doJoins(Set<? extends Join<?, ?>> joins, Join<?, ?> root) {
    for (Join<?, ?> join : joins) {
        Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType());
        joined.alias(join.getAlias());
        doJoins(join.getJoins(), joined);
    }
}

আশা করি এটি কারও সময় সাশ্রয় করবে।

কারণ আইএমএইচও জেপিএ ক্রিটারিয়া এপিআই স্বজ্ঞাত নয় এবং বেশ পাঠযোগ্য।


2
@ স্পেশালাইজ্ট অবশ্যই এটি নিখুঁত নয় - উদাহরণস্বরূপ উপরের সমাধানটি এখনও ফেচসে পুনরাবৃত্ত হয়ে যোগ দিচ্ছে। তবে আপনি কি ভাবেন যে কেবল এই কারণে আমার নিজের ভাবনাগুলি ভাগ করা উচিত নয়? আইএমএইচও ভাগ করে নেওয়ার জ্ঞান হ'ল স্ট্যাকওভারফো-এর মূল ধারণা।
জি ডেমেকি

ডাটাবেসগুলিতে পুনরাবৃত্তি হ'ল সর্বদা সবচেয়ে খারাপ সমাধান কল্পনাযোগ্য ... এটি একটি শিক্ষানবিশদের ভুল।
specializt

@ স্পেশালিজ্ট recursion on databases? আমি এপিআই স্তরে পুনরাবৃত্তির কথা বলছিলাম। এই ধারণাগুলি গুলিয়ে ফেলবেন না :-) জেপিএ খুব পাওয়ারফুল / জটিল এপিআই নিয়ে আসে যা আপনাকে একক ক্যোয়ারিতে একাধিক যোগদান / ফেচ / সমষ্টি / উপকরণ ইত্যাদি করতে দেয়। গণনার সময় আপনাকে এটি মোকাবেলা করতে হবে।
জি ডেমেকি

1
স্পষ্টতই আপনি এখনও বুঝতে পারেন নি যে জেপিএ কীভাবে কাজ করে - আপনার বেশিরভাগ সংখ্যক মানদণ্ড যথাযথ ডাটাবেস অনুসন্ধানগুলিতে ম্যাপ করা হবে, এইগুলি (অত্যন্ত উদ্ভট) সহ যোগদান করে। সক্রিয় করুন SQL এর আউটপুট এবং আপনার ভুল পালন - না "এপিআই স্তর" আছে, JPA একটি বিমূর্ততা স্তর
specializt

সম্ভবত, আপনি অনেক ক্যাসকেড জিনগুলি দেখতে পাবেন - কারণ জেপিএ এখনও স্বয়ংক্রিয়ভাবে এসকিউএল ফাংশন তৈরি করতে পারে না; কিন্তু যে পরিবর্তন হবে একদা ... সম্ভবত JPA 3, আমি এই জিনিস সম্পর্কে আলোচনা প্রত্যাহার
specializt

5

আপনার ব্যবহার করা জেপিএ 2 বাস্তবায়নের উপর নির্ভর করে এটি কিছুটা জটিল, এটি এক্লিপ্লেলিংক ২.৪.১ এর জন্য কাজ করে, তবে হাইবারনেটের পক্ষে নয়, এখানে এক্সিলিপলিংকের জন্য একটি জেনেরিক ক্রিটারিয়াক্যারি গণনা রয়েছে:

public static Long count(final EntityManager em, final CriteriaQuery<?> criteria)
  {
    final CriteriaBuilder builder=em.getCriteriaBuilder();
    final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);
    countCriteria.select(builder.count(criteria.getRoots().iterator().next()));
    final Predicate
            groupRestriction=criteria.getGroupRestriction(),
            fromRestriction=criteria.getRestriction();
    if(groupRestriction != null){
      countCriteria.having(groupRestriction);
    }
    if(fromRestriction != null){
      countCriteria.where(fromRestriction);
    }
    countCriteria.groupBy(criteria.getGroupList());
    countCriteria.distinct(criteria.isDistinct());
    return em.createQuery(countCriteria).getSingleResult();
  }

অন্য দিন আমি ইলিপ্লেলিংক থেকে হাইবারনেটে স্থানান্তরিত হয়েছি এবং আমার গণনা ফাংশনটি নিম্নলিখিতটিতে পরিবর্তন করতে হয়েছিলাম, তাই নির্দ্বিধায় এই সমস্যার সমাধান করা যেমন একটি কঠিন সমস্যা, এটি আপনার ক্ষেত্রে কার্যকর নাও হতে পারে, এটি হাইবারনেট থেকেই কার্যকর ছিল ৪.x, লক্ষ্য করুন যে মূলটি কোনটি অনুমান করার চেষ্টা করি না, পরিবর্তে আমি এটিকে প্রশ্নের সমাধান থেকে পাস করি যাতে সমস্যার সমাধান হয়, অনেকগুলি দ্ব্যর্থক কোণার অনুমান করার চেষ্টা করা হয়:

  public static <T> long count(EntityManager em,Root<T> root,CriteriaQuery<T> criteria)
  {
    final CriteriaBuilder builder=em.getCriteriaBuilder();
    final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);

    countCriteria.select(builder.count(root));

    for(Root<?> fromRoot : criteria.getRoots()){
      countCriteria.getRoots().add(fromRoot);
    }

    final Predicate whereRestriction=criteria.getRestriction();
    if(whereRestriction!=null){
      countCriteria.where(whereRestriction);
    }

    final Predicate groupRestriction=criteria.getGroupRestriction();
    if(groupRestriction!=null){
      countCriteria.having(groupRestriction);
    }

    countCriteria.groupBy(criteria.getGroupList());
    countCriteria.distinct(criteria.isDistinct());
    return em.createQuery(countCriteria).getSingleResult();
  }

যদি ক্যোয়ারী (গুলি) যোগদান করেছে?
ডেভ

আমি মনে করি যে একমাত্র কেইসই বিপজ্জনক হতে পারে যখন আপনি বামে যোগদান করেন এবং বাছাই মূলটি মূল সত্তা নয়। অন্যথায় এটি কোনও বিষয় নয়, কারণ বাছাই করা সত্তা নির্বিশেষে গণনাটি একই হবে। বাম যোগদান সংস্থাগুলি হিসাবে, আমি যথেষ্ট নিশ্চিত যে নির্বাচনের প্রথম সত্তাটি হল একটি রেফারেন্স, উদাহরণস্বরূপ, আপনার যদি শিক্ষার্থীরা কোর্সে যোগ দেয় তবে ছাত্রকে বাছাই স্বাভাবিক জিনিস হওয়া উচিত কারণ সেখানে কোর্স থাকতে পারে না যে শিক্ষার্থী নেই নাম নথিভুক্ত।
গুইডো মদিনা

1
যদি মূল কোয়েরিটি গ্রুপ-এর ক্যোয়ারী হয় তবে ফলাফলটি প্রতিটি গ্রুপের জন্য একটি গণনা হবে। যদি আমরা একটি সাবকিউয়েরিতে একটি মানদণ্ড তৈরি করতে পারি, তবে সাব-কোয়েরিটি গণনা করুন, এটি সমস্ত ক্ষেত্রে কার্যকর হবে। আমরা কি ওটা করতে পারি?
ডেভ

হাই @ ডেভ, আমি আপনার মত একই সিদ্ধান্তে পৌঁছেছি, আসল সমাধান হ'ল ক্যোয়ারিকে সাবকিউরিতে রূপান্তর করতে সক্ষম হওয়া, এটি সমস্ত ক্ষেত্রে এমনকি একটি গ্রুপবিয়ের পরেও সারি গণনার জন্য কাজ করবে। প্রকৃতপক্ষে ক্রিটারিয়াকোয়ারি এবং সাবকিউয়ের জন্য বিভিন্ন ক্লাজ কেন বা লীসে তারা ভাগ করে নেওয়া সাধারণ ইন্টারফেস, অ্যাবস্ট্রাক্টকিউরিটি কোনও নির্বাচন পদ্ধতি নির্ধারণ করে না তার কারণ খুঁজে পাচ্ছি না। এ কারণে প্রায় কোনও কিছুর পুনরায় ব্যবহার করার উপায় নেই। সারিগুলি গণনা করার জন্য কোয়েরি দ্বারা গ্র্যাপডকে পুনঃব্যবহার করার জন্য আপনি কি একটি পরিষ্কার সমাধান খুঁজে পেয়েছেন?
আমান্ডা তারাফা মাস

1

আপনি প্রজেকশনগুলিও ব্যবহার করতে পারেন:

ProjectionList projection = Projections.projectionList();
projection.add(Projections.rowCount());
criteria.setProjection(projection);

Long totalRows = (Long) criteria.list().get(0);

1
আমি আশঙ্কা করছি প্রজেকশনস এপিআই হাইবারনেট নির্দিষ্ট তবে প্রশ্নটি জেপিএ 2 সম্পর্কে জিজ্ঞাসা করছে
21:39

তবুও, আমি এটি একটি দরকারী সংযোজন বলে মনে করি, তবে এটির একটি মন্তব্য হওয়া উচিত ছিল। পূর্ণ হাইবারনেট-নির্দিষ্ট উত্তর অন্তর্ভুক্ত করতে আপনি কি নিজের উত্তরটি প্রসারিত করতে পারেন?
বেনি বোত্তেমা

জেরসনজারাগোসিন একমত, তবে মন্তব্যে কোনও কোড ব্লক নেই
পাভেল ইভস্টিগিনিভ

0

স্প্রিং ডেটা জেপা সহ, আমরা এই পদ্ধতিটি ব্যবহার করতে পারি:

    /*
     * (non-Javadoc)
     * @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#count(org.springframework.data.jpa.domain.Specification)
     */
    @Override
    public long count(@Nullable Specification<T> spec) {
        return executeCountQuery(getCountQuery(spec, getDomainClass()));
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.