स्प्रिंग जेपीए विशिष्ट कॉलम का चयन


146

मैं सभी डेटाबेस संचालन करने के लिए स्प्रिंग जेपीए का उपयोग कर रहा हूं। हालाँकि मुझे नहीं पता कि स्प्रिंग जेपीए में एक तालिका से विशिष्ट कॉलम कैसे चुनें?

उदाहरण के लिए:
SELECT projectId, projectName FROM projects



जेपीए के पीछे विशिष्ट क्षेत्रों की तलाश नहीं करने के पीछे विचार यह है कि लागत (दक्षता वार) तालिका के एक पंक्ति से एक कॉलम या सभी कॉलम लाने के लिए समान है।
9

7
@Desorder - लागत हमेशा समान नहीं होती है। यह संभवत: सरल, आदिम प्रकार के डेटाटिप्स के लिए एक बड़ी बात नहीं है, लेकिन इस पृष्ठ पर मैंने जो कारण समाप्त किया है, वह इसलिए है क्योंकि मैंने देखा कि एक सरल "सूची दस्तावेज" क्वेरी धीमी गति से चल रही थी। उस इकाई में एक BLOB कॉलम है (इसे फ़ाइल अपलोड / संग्रहण के लिए आवश्यक है) और मुझे संदेह है कि यह धीमा है क्योंकि यह BLOB को मेमोरी में लोड कर रहा है, भले ही वे डॉक्स को सूचीबद्ध करने के लिए आवश्यक न हों।
jm0

@ jm0 जहाँ तक आपको याद है, कितने टेबल में BLOB कॉलम थे?
डेसऑर्डर

1
@Desorder यह सिर्फ एक तालिका थी, लेकिन मैं एक "सूची" फ़ंक्शन (मल्टीरो - दी गई आईडी द्वारा बनाए गए सभी डॉक्स सूची) कर रहा था। इस मुद्दे पर ध्यान देने का एकमात्र कारण यह था कि यह सरल सूची क्वेरी कई सेकंड ले रही थी, जबकि अन्य तालिकाओं पर अधिक जटिल प्रश्न लगभग तुरंत हो रहे थे। एक बार जब मुझे एहसास हुआ, मुझे पता था कि यह अधिक से अधिक पीड़ित होगा क्योंकि पंक्तियों को जोड़ा जाता है क्योंकि स्प्रिंग जेपीए प्रत्येक बीएलओबी को स्मृति में लोड कर रहा है यहां तक ​​कि उनका उपयोग नहीं किया जाता है। मुझे स्प्रिंग डेटा के लिए एक सभ्य समाधान मिला (नीचे पोस्ट किया गया) लेकिन मुझे लगता है कि मेरे पास एक और भी बेहतर है जो शुद्ध जेपीए एनोटेशन है, मैं tmrw पोस्ट करूँगा अगर यह काम करता है
jm0

जवाबों:


75

आप इस तरह एक वर्ग से एनोटेशन nativeQuery = trueमें सेट कर सकते हैं :@QueryRepository

public static final String FIND_PROJECTS = "SELECT projectId, projectName FROM projects";

@Query(value = FIND_PROJECTS, nativeQuery = true)
public List<Object[]> findProjects();

ध्यान दें कि आपको मैपिंग स्वयं करनी होगी। जब तक आपको वास्तव में केवल उन दो मूल्यों की आवश्यकता नहीं होती है, तब तक नियमित रूप से मैप किए गए लुकअप का उपयोग करना शायद आसान है:

public List<Project> findAll()

यह संभवतः स्प्रिंग डेटा डॉक्स को भी देखने लायक है ।


5
देशी प्रश्नों की कोई आवश्यकता नहीं है। आपको उन्हें उपयोग करने से बचना चाहिए, क्योंकि वे JPQL के फायदे को बर्बाद करते हैं। जवाब देखिए।
दर्शन २

1
मेरे लिए मुझे विशेषता नाम के FIND_PROJECTSसाथ पहली विशेषता (ऊपर ) को अर्हता प्राप्त करनी थी value(इसलिए यदि यह मेरा कोड होता तो मुझे इसे लिखना होता @Query(value = FIND_PROJECTS, nativeQuery = true), आदि
smeeb

172

आप स्प्रिंग डेटा जेपीए (डॉक्टर) से अनुमानों का उपयोग कर सकते हैं । आपके मामले में, इंटरफ़ेस बनाएँ:

interface ProjectIdAndName{
    String getId();
    String getName();
}

और अपने भंडार में निम्नलिखित विधि जोड़ें

List<ProjectIdAndName> findAll();

11
यह एक साफ समाधान है। इसमें बॉयलर टेम्प्लेट हो सकता है, लेकिन इंटरफ़ेस इकाई का आंतरिक वर्ग हो सकता है। इसे काफी साफ करना।
आइकमन

1
भयानक, बस अपने इकाई पर इंटरफ़ेस को लागू नहीं करने के लिए याद रखें या यह काम नहीं करेगा
alizelzele

1
अनुमानित इंटरफ़ेस कहाँ जाता है? अपनी स्वयं की फ़ाइल में या इसे सार्वजनिक इंटरफ़ेस में शामिल किया जा सकता है जो पूर्ण इकाई गुण लौटाता है?
मिचो रिजो

8
यह समाधान JpaRepository को विस्तारित करते समय काम नहीं करता है, कोई भी एक समाधान जानता है?
जर्मन

4
आप findAll () का उपयोग नहीं कर सकते हैं; के रूप में यह JPARepositorys विधि के साथ संघर्ष करेगा। आपको सूची <ProjectIdAndName> findAllBy () जैसी किसी चीज़ का उपयोग करने की आवश्यकता है;
कोड_मोड

137

मैं विशेष रूप से वाक्यविन्यास पसंद नहीं करता (यह थोड़ा सा हैक होता है ...) लेकिन यह सबसे सुरुचिपूर्ण समाधान है जिसे मैं खोजने में सक्षम था (यह जेपीए रिपॉजिटरी वर्ग में एक कस्टम JPQL क्वेरी का उपयोग करता है):

@Query("select new com.foo.bar.entity.Document(d.docId, d.filename) from Document d where d.filterCol = ?1")
List<Document> findDocumentsForListing(String filterValue);

फिर निश्चित रूप से, आपको बस Documentउस स्वीकारकर्ता के लिए एक कंस्ट्रक्टर प्रदान करना होगा docIdऔर filenameजैसा कि निर्माता आर्ग करते हैं।


9
(और btw मैंने सत्यापित किया, अगर "दस्तावेज़" आयात किया गया है, तो आपको पूरी तरह से योग्य क्लासनाम प्रदान करने की आवश्यकता नहीं है - बस यह इस तरह से था क्योंकि यह एकमात्र नमूना है जिसे मैं खोजने में सक्षम था)
jm0

यह स्वीकृत उत्तर होना चाहिए। यह पूरी तरह से काम करता है और वास्तव में केवल आवश्यक क्षेत्रों का चयन करता है।
योनातन विल्कोफ

1
अनावश्यक फ़ील्ड भी शामिल हैं, लेकिन 'शून्य' मान के साथ, क्या वे फ़ील्ड मेमोरी पर कब्जा कर लेंगे?
गबलर

हां, लेकिन इतना न्यूनतम कि अधिकांश मामलों में इसके आसपास के इंजीनियर के लिए प्रयास करना वास्तव में हास्यास्पद होगा - stackoverflow.com/questions/2430655/ ... आपको इन क्षेत्रों के बिना विशेष हल्की वस्तुएं बनानी होंगी और उन्हें उसी पर इंगित करना होगा तालिका? ओआरएम का उपयोग करते समय और अपने रिश्तों के लिए उनका लाभ उठाते हुए आईएमओ अवांछित है ... हाइपर-ऑप्टिमाइज़ेशन शायद कुछ हल्के क्वेरी डीएसएल का उपयोग करके और सीधे डीटीओ के लिए मैपिंग के दायरे में अधिक है, और फिर भी मुझे लगता है कि अतिरेक को
खारिज कर

2
jm0 यह पूरी तरह से योग्य classname के बिना मेरे लिए काम नहीं करता था, हालांकि इसे आयात किया गया था। यह हालांकि सफलतापूर्वक संकलित किया।
हाइजेनबर्ग

20

मेरी स्थिति में, मुझे केवल json परिणाम की आवश्यकता है, और यह मेरे लिए काम करता है:

public interface SchoolRepository extends JpaRepository<School,Integer> {
    @Query("select s.id, s.name from School s")
    List<Object> getSchoolIdAndName();
}

नियंत्रक में:

@Autowired
private SchoolRepository schoolRepository;

@ResponseBody
@RequestMapping("getschoolidandname.do")
public List<Object> getSchool() {
    List<Object> schools = schoolRepository.getSchoolIdAndName();
    return schools;
}

2
आपको Objectmpr द्वारा बताए गए कस्टम इंटरफ़ेस के साथ स्थानापन्न होना चाहिए ।
त्रुटिपूर्ण रूप से

14

मेरे मामले में मैंने उन क्षेत्रों के बिना एक अलग इकाई वर्ग बनाया है जिनकी आवश्यकता नहीं है (केवल उन क्षेत्रों के साथ जिनकी आवश्यकता है)।

इकाई को उसी तालिका में मैप करें। अब जब सभी स्तंभों की आवश्यकता होती है तो मैं पुरानी इकाई का उपयोग करता हूं, जब केवल कुछ स्तंभों की आवश्यकता होती है, तो मैं लाइट इकाई का उपयोग करता हूं।

जैसे

@Entity
@Table(name = "user")
Class User{
         @Column(name = "id", unique=true, nullable=false)
         int id;
         @Column(name = "name", nullable=false)
         String name;
         @Column(name = "address", nullable=false)
         Address address;
}

आप कुछ ऐसा बना सकते हैं:

@Entity
@Table(name = "user")
Class UserLite{
         @Column(name = "id", unique=true, nullable=false)
         int id;
         @Column(name = "name", nullable=false)
         String name;
}

यह तब काम करता है जब आप कॉलम को जानते हैं (और यह बदलने वाला नहीं है)।

यदि आपको स्तंभों को गतिशील रूप से तय करने की आवश्यकता है तो काम नहीं करेगा।


हाय साचिन, मुझे एक संदेह है यदि मैं इकाई बनाऊंगा जैसा कि आप ऊपर उल्लेख करते हैं। जब JPA चलेगा और यह उपयोगकर्ता के नाम के साथ तालिका बनाने का प्रयास करेगा। कौन सी इकाई का उपयोग करेगा
user3364549

3
जेपीए के साथ एक तालिका कभी न बनाएं, डीबी में मैन्युअल रूप से अपनी तालिकाएं बनाएं, जेपीए का उपयोग संबंध विश्व को ऑब्जेक्ट वर्ल्ड में मैप करने के लिए करें।
सचिन शर्मा

आप यहाँ विरासत का उपयोग क्यों नहीं कर सकते?
डेडबग

8

मुझे लगता है कि QueryDSL का उपयोग करने का आसान तरीका वसंत-डेटा के साथ आता है।

आपके प्रश्न का उपयोग करके उत्तर हो सकता है

JPAQuery query = new JPAQuery(entityManager);
List<Tuple> result = query.from(projects).list(project.projectId, project.projectName);
for (Tuple row : result) {
 System.out.println("project ID " + row.get(project.projectId));
 System.out.println("project Name " + row.get(project.projectName)); 
}}

इकाई प्रबंधक को स्वतः प्राप्त किया जा सकता है और आप हमेशा उपयोग * QL भाषा के बिना ऑब्जेक्ट और क्लैस के साथ काम करेंगे।

जैसा कि आप लिंक में देख सकते हैं कि अंतिम विकल्प लगता है, लगभग मेरे लिए, अधिक सुरुचिपूर्ण, अर्थात्, परिणाम को संग्रहीत करने के लिए डीटीओ का उपयोग करना। आपके उदाहरण पर लागू होगा:

JPAQuery query = new JPAQuery(entityManager);
QProject project = QProject.project;
List<ProjectDTO> dtos = query.from(project).list(new QProjectDTO(project.projectId, project.projectName));

ProjectDTO को परिभाषित करना:

class ProjectDTO {

 private long id;
 private String name;
 @QueryProjection
 public ProjectDTO(long projectId, String projectName){
   this.id = projectId;
   this.name = projectName;
 }
 public String getProjectId(){ ... }
 public String getProjectName(){....}
}

5

नए वसंत संस्करणों के साथ एक निम्नानुसार कर सकता है:

यदि देशी क्वेरी का उपयोग नहीं किया जा रहा है तो यह नीचे दिया जा सकता है:

public interface ProjectMini {
    String getProjectId();
    String getProjectName();
}

public interface ProjectRepository extends JpaRepository<Project, String> { 
    @Query("SELECT p FROM Project p")
    List<ProjectMini> findAllProjectsMini();
}

देशी क्वेरी का उपयोग नीचे के रूप में किया जा सकता है:

public interface ProjectRepository extends JpaRepository<Project, String> { 
    @Query(value = "SELECT projectId, projectName FROM project", nativeQuery = true)
    List<ProjectMini> findAllProjectsMini();
}

विस्तार के लिए डॉक्स की जांच करें


4

मेरी राय में यह महान समाधान है:

interface PersonRepository extends Repository<Person, UUID> {

    <T> Collection<T> findByLastname(String lastname, Class<T> type);
}

और इसका उपयोग करना पसंद है

void someMethod(PersonRepository people) {

  Collection<Person> aggregates =
    people.findByLastname("Matthews", Person.class);

  Collection<NamesOnly> aggregates =
    people.findByLastname("Matthews", NamesOnly.class);
}

क्यों संग्रह के बजाय सूची <टी> वापस नहीं करते हैं?!
अब्दुल्ला खान

@ अब्दुल्लाहकहान क्योंकि परिणाम हमेशा एक आदेश नहीं हो सकता है।
रवि सांवल

4

स्प्रिंग डेटा जेपीए का उपयोग करते हुए डेटाबेस से विशिष्ट कॉलम का चयन करने का प्रावधान है

---- DAOImpl में ----

@Override
    @Transactional
    public List<Employee> getAllEmployee() throws Exception {
    LOGGER.info("Inside getAllEmployee");
    List<Employee> empList = empRepo.getNameAndCityOnly();
    return empList;
    }

---- रेपो में ----

public interface EmployeeRepository extends CrudRepository<Employee,Integer> {
    @Query("select e.name, e.city from Employee e" )
    List<Employee> getNameAndCityOnly();
}

इसने मेरे मामले में 100% काम किया। धन्यवाद।


2

आप JPQL का उपयोग कर सकते हैं:

TypedQuery <Object[]> query = em.createQuery(
  "SELECT p.projectId, p.projectName FROM projects AS p", Object[].class);

List<Object[]> results = query.getResultList();

या आप देशी sql क्वेरी का उपयोग कर सकते हैं।

Query query = em.createNativeQuery("sql statement");
List<Object[]> results = query.getResultList();

2

nullदेशी एसक्यूएल में फ़ील्ड मान के रूप में निर्दिष्ट करना संभव है।

@Query(value = "select p.id, p.uid, p.title, null as documentation, p.ptype " +
            " from projects p " +
            "where p.uid = (:uid)" +
            "  and p.ptype = 'P'", nativeQuery = true)
Project findInfoByUid(@Param("uid") String uid);

2

आप नीचे दिए गए कोड को अपने रिपॉजिटरी इंटरफ़ेस क्लास में लागू कर सकते हैं।

Unitname का अर्थ है कि आपका डेटाबेस तालिका नाम जैसे प्रोजेक्ट्स। और सूची का मतलब है प्रोजेक्ट आपके प्रोजेक्ट्स में एंटिटी क्लास है।

@Query(value="select p from #{#entityName} p where p.id=:projectId and p.projectName=:projectName")

List<Project> findAll(@Param("projectId") int projectId, @Param("projectName") String projectName);

0

देशी क्वेरी का उपयोग करना:

Query query = entityManager.createNativeQuery("SELECT projectId, projectName FROM projects");
List result = query.getResultList();

0

आप @ जॉम्जी द्वारा सुझाए गए उत्तर का उपयोग कर सकते हैं, और:

  • इकाई वर्ग के बाहर एक अलग फ़ाइल में इंटरफ़ेस रखें;
  • देशी क्वेरी का उपयोग करें या नहीं (आपकी आवश्यकताओं पर निर्भर विकल्प);
  • findAll()इस उद्देश्य के लिए विधि को ओवरराइड न करें, लेकिन अपनी पसंद के नाम का उपयोग करें;
  • Listअपने नए इंटरफ़ेस (जैसे List<SmallProject>) के साथ एक पैराड्राइक को वापस करना याद रखें ।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.