কীভাবে কোনও স্প্রিং ডেটা জেপিএ গ্রুপ থেকে একটি কাস্টম অবজেক্ট ফেরত পাবেন


115

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

@Query(value = "select count(v) as cnt, v.answer from Survey v group by v.answer")
public List<?> findSurveyCount();

এটি কাজ করছে এবং ফলাফলটি নিম্নলিখিতভাবে পাওয়া যায়:

[
  [1, "a1"],
  [2, "a2"]
]

আমি এই জাতীয় কিছু পেতে চাই:

[
  { "cnt":1, "answer":"a1" },
  { "cnt":2, "answer":"a2" }
]

আমি কীভাবে এটি অর্জন করতে পারি?

উত্তর:


249

জেপিকিউএল প্রশ্নের জন্য সমাধান

এটি JPA নির্দিষ্টকরণের মধ্যে JPQL প্রশ্নের জন্য সমর্থিত ।

পদক্ষেপ 1 : একটি সাধারণ শিমের বর্গ ঘোষণা করুন

package com.path.to;

public class SurveyAnswerStatistics {
  private String answer;
  private Long   cnt;

  public SurveyAnswerStatistics(String answer, Long cnt) {
    this.answer = answer;
    this.count  = cnt;
  }
}

পদক্ষেপ 2 : সঞ্চিত প্রতিস্থাপন পদ্ধতি থেকে দৃষ্টান্তগুলি ফেরত দিন

public interface SurveyRepository extends CrudRepository<Survey, Long> {
    @Query("SELECT " +
           "    new com.path.to.SurveyAnswerStatistics(v.answer, COUNT(v)) " +
           "FROM " +
           "    Survey v " +
           "GROUP BY " +
           "    v.answer")
    List<SurveyAnswerStatistics> findSurveyCount();
}

গুরুত্বপূর্ণ নোট

  1. প্যাকেজের নাম সহ শিম শ্রেণীর সম্পূর্ণরূপে যোগ্য পথ সরবরাহ নিশ্চিত করুন। উদাহরণস্বরূপ, যদি মটরশুটি শ্রেণি কল করা হয় MyBeanএবং এটি প্যাকেজে থাকে তবে শিমের com.path.toসম্পূর্ণরূপে যোগ্য পাথ হবে com.path.to.MyBean। কেবল সরবরাহ করা কার্যকর MyBeanহবে না (যদি না বিন বিন্যাস ডিফল্ট প্যাকেজে না থাকে)।
  2. newকীওয়ার্ডটি ব্যবহার করে শিমের বর্গ নির্মাণকারীকে কল করতে ভুলবেন না । SELECT new com.path.to.MyBean(...)কাজ করবে, যেখানে SELECT com.path.to.MyBean(...)হবে না।
  3. শিম নির্মাতা হিসাবে প্রত্যাশার সাথে ঠিক একই ক্রমে বৈশিষ্ট্যগুলি পাস করার বিষয়টি নিশ্চিত করুন। ভিন্ন ক্রমে গুণাবলী পাস করার চেষ্টা করা ব্যতিক্রম ঘটায়।
  4. নিশ্চিত করুন যে ক্যোয়ারীটি একটি বৈধ জেপিএ ক্যোয়ারী, এটি, এটি কোনও স্থানীয় কোয়েরি নয়। @Query("SELECT ..."), বা @Query(value = "SELECT ..."), বা @Query(value = "SELECT ...", nativeQuery = false)কাজ করবে, যেখানে @Query(value = "SELECT ...", nativeQuery = true)কাজ করবে না। এর কারণ হ'ল দেশীয় কোয়েরিগুলি জেপিএ সরবরাহকারীকে সংশোধন ছাড়াই পাস করা হয় এবং অন্তর্নিহিত আরডিবিএমএসের বিরুদ্ধে কার্যকর হয়। যেহেতু newএবং com.path.to.MyBeanবৈধ এসকিউএল কীওয়ার্ড নয়, আরডিবিএমএস তার পরে একটি ব্যতিক্রম ছুঁড়ে দেয়।

দেশীয় প্রশ্নের জন্য সমাধান

উপরে উল্লিখিত হিসাবে, new ...বাক্য গঠনটি একটি জেপিএ-সমর্থিত প্রক্রিয়া এবং সমস্ত জেপিএ সরবরাহকারীদের সাথে কাজ করে। তবে, যদি কোয়েরিটি নিজেই জেপিএ কোয়েরি না হয়, এটি একটি নেটিভ কোয়েরি, new ...বাক্যটি সরাসরি অন্তর্নিহিত আরডিবিএমএসে প্রেরণ করা হওয়ায় সিনট্যাক্সটি কাজ করবে না, যা মূলশব্দটি বোঝে না newকারণ এটি এর অংশ নয় not এসকিউএল স্ট্যান্ডার্ড।

এ জাতীয় পরিস্থিতিতে, শিমের ক্লাসগুলি স্প্রিং ডেটা প্রজেকশন ইন্টারফেসের সাথে প্রতিস্থাপন করা দরকার ।

পদক্ষেপ 1 : একটি অভিক্ষেপ ইন্টারফেস ঘোষণা করুন

package com.path.to;

public interface SurveyAnswerStatistics {
  String getAnswer();

  int getCnt();
}

পদক্ষেপ 2 : ক্যোয়ারী থেকে অনুমানিত বৈশিষ্ট্যগুলি ফিরিয়ে দিন

public interface SurveyRepository extends CrudRepository<Survey, Long> {
    @Query(nativeQuery = true, value =
           "SELECT " +
           "    v.answer AS answer, COUNT(v) AS cnt " +
           "FROM " +
           "    Survey v " +
           "GROUP BY " +
           "    v.answer")
    List<SurveyAnswerStatistics> findSurveyCount();
}

ASদ্ব্যর্থহীন ম্যাপিংয়ের জন্য প্রোজেক্ট বৈশিষ্ট্যগুলিতে ফলাফল ক্ষেত্রগুলিতে মানচিত্রের জন্য এসকিউএল কীওয়ার্ডটি ব্যবহার করুন ।


1
এটি কাজ করছে না, গুলি চালানোর ত্রুটি:Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [SurveyAnswerReport] [select new SurveyAnswerReport(v.answer,count(v.id)) from com.furniturepool.domain.Survey v group by v.answer] at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1750) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677) at org.hibernate.jpa.spi.AbstractEnti..........
প্রণব সি বালান

কি এই হল SurveyAnswerReport আপনার আউটপুটে। আমি ধরে নিয়েছি আপনি SurveyAnswerStatistics আপনার নিজের শ্রেণীর সাথে প্রতিস্থাপন করেছেন SurveyAnswerReport। আপনার সম্পূর্ণ যোগ্য শ্রেণীর নাম উল্লেখ করা দরকার।
বুন্টি

8
শিম শ্রেণি অবশ্যই পুরোপুরি যোগ্য হতে হবে, অর্থাত্, সম্পূর্ণ প্যাকেজের নাম অন্তর্ভুক্ত করুন। কিছু একটা com.domain.dto.SurveyAnswerReport
মনিশ

2
আমি 'java.lang.IllegalArgumentException পেয়েছি: পার্সেস্ট্যান্ট এন্টিটি নালাম হওয়া উচিত না! `যখন আমি আমার কাছ থেকে কাস্টম প্রকারটি চেষ্টা করি JpaRepository? কিছু কনফিগারেশন আমি মিস করেছি?
মারিওশ

1
নেটিভ ক্যোয়ারী ব্যতিক্রমগুলি ব্যবহার করার সময় বলে: নেস্টেড ব্যতিক্রম java.lang.IllegalArgumentException: একটি পরিচালিত প্রকার নয়: শ্রেণি ... কেন এই খুশি হওয়া উচিত?
মিখাইল ঝেঝেন্তি

20

এই এসকিউএল ক্যোয়ারী <অবজেক্ট []> তালিকাটি দেবে।

আপনি এটি এইভাবে করতে পারেন:

 @RestController
 @RequestMapping("/survey")
 public class SurveyController {

   @Autowired
   private SurveyRepository surveyRepository;

     @RequestMapping(value = "/find", method =  RequestMethod.GET)
     public Map<Long,String> findSurvey(){
       List<Object[]> result = surveyRepository.findSurveyCount();
       Map<Long,String> map = null;
       if(result != null && !result.isEmpty()){
          map = new HashMap<Long,String>();
          for (Object[] object : result) {
            map.put(((Long)object[0]),object[1]);
          }
       }
     return map;
     }
 }

1
এই প্রশ্নের আপনার প্রতিক্রিয়া জন্য ধন্যবাদ। এটি ছিল খাস্তা এবং স্পষ্ট
ধীররাজ আর

@ মানিশ ধন্যবাদ আপনি আমার রাতের ঘুম বাঁচিয়েছেন, আপনার পদ্ধতিটি কবজির মতো কাজ করেছে !!!!!!!
ভিনিল

15

আমি জানি এটি একটি পুরানো প্রশ্ন এবং এর উত্তর ইতিমধ্যে দেওয়া হয়ে গেছে, তবে এখানে আরও একটি পদ্ধতি রয়েছে:

@Query("select new map(count(v) as cnt, v.answer) from Survey v group by v.answer")
public List<?> findSurveyCount();

আমি আপনার উত্তরটি পছন্দ করি কারণ এটি আমাকে নতুন শ্রেণি বা ইন্টারফেস তৈরি করতে বাধ্য করে না। এটা আমার জন্য কাজ করেছে।
ইউরি হাসলে আরাজাতো

ঠিকঠাক কাজ করে তবে আমি জেনেরিকের পরিবর্তে মানচিত্রের ব্যবহারকে অগ্রাধিকার দেব? মানচিত্রটি কী (0) এবং মান (1) হিসাবে তাদের অ্যাক্সেস করতে দেবে
সামিম আফতাব আহমেদ

10

ইন্টারফেস ব্যবহার করে আপনি সহজ কোড পেতে পারেন। কনস্ট্রাক্টরগুলিকে ম্যানুয়ালি কল করার দরকার নেই

পদক্ষেপ 1 : প্রয়োজনীয় ক্ষেত্রগুলির সাথে ইন্টারফ্রেস ঘোষণা করুন:

public interface SurveyAnswerStatistics {

  String getAnswer();
  Long getCnt();

}

পদক্ষেপ 2 : ইন্টারফেসে গেটর হিসাবে একই নামের কলামগুলি নির্বাচন করুন এবং সংগ্রহস্থল পদ্ধতি থেকে ইন্টারফ্রেস রিটার্ন করুন:

public interface SurveyRepository extends CrudRepository<Survey, Long> {

    @Query("select v.answer as answer, count(v) as cnt " +
           "from Survey v " +
           "group by v.answer")
    List<SurveyAnswerStatistics> findSurveyCount();

}

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

এছাড়াও, সেখানে রয়েছে জরিপ শ্রেণি
মিখিল ঝেঝেন্তি

6

নিশ্চিত কাস্টম পোজো ক্লাসটি সংজ্ঞায়িত করুন নিশ্চিত করে বলুন ক্যুয়্যারঅ্যানালিটিক্স এবং আপনার কাস্টম পোজো ক্লাসে ক্যোয়ারী ফেরত মান সংরক্ষণ করুন

@Query(value = "select new com.xxx.xxx.class.SureveyQueryAnalytics(s.answer, count(sv)) from Survey s group by s.answer")
List<SureveyQueryAnalytics> calculateSurveyCount();


3

আমি কোয়েরি স্ট্রিংগুলিতে জাভা টাইপের নাম পছন্দ করি না এবং এটি নির্দিষ্ট কন্সট্রাক্টরের সাথে পরিচালনা করি। স্প্রিং জেপিএ হ্যাশম্যাপ প্যারামিটারে কোয়েরির ফলাফল সহ স্পষ্টভাবে কনস্ট্রাক্টরকে কল করে:

@Getter
public class SurveyAnswerStatistics {
  public static final String PROP_ANSWER = "answer";
  public static final String PROP_CNT = "cnt";

  private String answer;
  private Long   cnt;

  public SurveyAnswerStatistics(HashMap<String, Object> values) {
    this.answer = (String) values.get(PROP_ANSWER);
    this.count  = (Long) values.get(PROP_CNT);
  }
}

@Query("SELECT v.answer as "+PROP_ANSWER+", count(v) as "+PROP_CNT+" FROM  Survey v GROUP BY v.answer")
List<SurveyAnswerStatistics> findSurveyCount();

কোডটি গেটারের সমাধানের জন্য লম্বোকের প্রয়োজন


@ গিটার কোডটি চালানোর আগে একটি ত্রুটি দেখায় এটি বস্তুর ধরণের নয়
ব্যবহারকারী 666

লম্বোক প্রয়োজন হয়। কোডটিতে কেবল একটি পাদটীকা যুক্ত হয়েছে।
we ই

1

আমি কেবল এই সমস্যাটি সমাধান করেছি:

  • ক্লাস-ভিত্তিক প্রকল্পগুলি কোয়েরি নেটিভ ( @Query(value = "SELECT ...", nativeQuery = true) এর সাথে কাজ করে না তাই আমি ইন্টারফেস ব্যবহার করে কাস্টম ডিটিও সংজ্ঞায়িত করার পরামর্শ দিই recommend
  • ডিটিও ব্যবহারের আগে ক্যোয়ারীটি সিনট্যাটিকভাবে সঠিক কিনা তা যাচাই করা উচিত

1

আমি একটি নেটিভ কোয়েরি ম্যাপ করতে কাস্টম ডিটিও (ইন্টারফেস) ব্যবহার করেছি - সবচেয়ে নমনীয় পদ্ধতির এবং রিফ্যাক্টরিং-নিরাপদ।

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


0
@Repository
public interface ExpenseRepo extends JpaRepository<Expense,Long> {
    List<Expense> findByCategoryId(Long categoryId);

    @Query(value = "select category.name,SUM(expense.amount) from expense JOIN category ON expense.category_id=category.id GROUP BY expense.category_id",nativeQuery = true)
    List<?> getAmountByCategory();

}

উপরের কোডটি আমার পক্ষে কাজ করেছিল।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.