JPA: POJO वर्ग संग्रह में सेट किए गए मूल क्वेरी परिणाम को कैसे परिवर्तित करें


174

मैं अपने प्रोजेक्ट में जेपीए का उपयोग कर रहा हूं।

मैं एक क्वेरी में आया था जिसमें मुझे पाँच तालिकाओं पर ज्वाइन ऑपरेशन करने की आवश्यकता थी। इसलिए मैंने एक देशी क्वेरी बनाई, जिसमें पाँच फ़ील्ड हैं।

अब मैं परिणाम वस्तु को जावा पीओजेओ क्लास में बदलना चाहता हूं जिसमें पांच स्ट्रिंग्स शामिल हैं।

क्या JJ में कोई भी तरीका है जो सीधे POJO ऑब्जेक्ट लिस्ट में आता है ??

मैं निम्नलिखित समाधान के लिए आया था ..

@NamedNativeQueries({  
    @NamedNativeQuery(  
        name = "nativeSQL",  
        query = "SELECT * FROM Actors",  
        resultClass = db.Actor.class),  
    @NamedNativeQuery(  
        name = "nativeSQL2",  
        query = "SELECT COUNT(*) FROM Actors",  
        resultClass = XXXXX) // <--------------- problem  
})  

अब यहां resultClass में, क्या हमें एक वर्ग प्रदान करने की आवश्यकता है जो वास्तविक JPA इकाई है? या हम इसे किसी भी JAVA POJO वर्ग में बदल सकते हैं जिसमें समान कॉलम नाम हैं?


इस उत्तर की जाँच करें। इसका पूरा उत्तर है: stackoverflow.com/a/50365522/3073945
Md। सजदुल करीम

वह जेपीए का उपयोग कर रहा है, वसंत का नहीं
उसे

जवाबों:


103

JPA एक SqlResultSetMappingऐसी सुविधा प्रदान करता है जो आपको अपनी मूल क्वेरी से निकाय में दिए गए रिटर्न को मैप करने की अनुमति देता हैया एक कस्टम वर्ग

EDIT JPA 1.0 गैर-इकाई वर्गों के लिए मैपिंग की अनुमति नहीं देता है। केवल JPA 2.1 में एक ConstructorResult को मानचित्र मानों में जोड़ने के लिए एक जावा वर्ग जोड़ा गया है।

इसके अलावा, ओपी की गिनती के लिए समस्या के लिए यह एक एकल के साथ परिणाम सेट मानचित्रण को परिभाषित करने के लिए पर्याप्त होना चाहिए ColumnResult


1
उत्तर के लिए धन्यवाद। यहाँ हम "@EityityResult" और "@FieldResult" एनोटेशन के साथ tha java एंटिटी क्लास के साथ इकाई के साथ अपना परिणाम मैप कर रहे हैं। कोई बात नहीं। लेकिन यहां मुझे अधिक स्पष्टता की आवश्यकता है। क्या यह आवश्यक है कि परिणाम के साथ जिस वर्ग की हम मैपिंग कर रहे हैं वह एक जेपीए इकाई वर्ग होना चाहिए? या हम एक साधारण POJO वर्ग का उपयोग कर सकते हैं जो एक इकाई खरीद नहीं है जिसके परिणाम सेट में कॉलम के रूप में सभी आवश्यक चर हैं।
गुंजन शाह

1
@ गुंजनशाह: यह जानने का सबसे अच्छा तरीका यह है कि इसे आजमाया जाए :) साथ ही, एक इकाई सिर्फ एक ही पूजो है, बस कुछ टिप्पणियों के साथ। जब तक आप इसे जारी रखने की कोशिश नहीं कर रहे हैं, तब तक यह एक पोजो रहेगा।
डेनिस तुलस्की

2
जब मैंने यह कोशिश की तो मुझे एक त्रुटि मिली कि कक्षा एक ज्ञात इकाई नहीं थी। मैंने मूल दृष्टिकोण का उपयोग करने की कोशिश करने के बजाय इस दृष्टिकोण stackoverflow.com/questions/5024533/… का उपयोग करके समाप्त किया ।
FGreg

2
@EdwinDalorzo: यह jpa 1.0 के लिए सही है। Jpa 2.1 में उन्होंने ConstructorResultएक पैरामीटर के रूप में जोड़ा है SqlResultSetMappingजो कि निर्माण में स्थापित सभी क्षेत्रों के साथ एक पूजो का उपयोग करने की अनुमति देता है। मैं जवाब अपडेट कर दूंगा।
डेनिस तुलस्की

4
मैं एक और कड़वा सच देखता हूं: ConstructorResult एक POJO को मैप कर सकता है .. लेकिन BUT ConstructorResult को केवल Entity क्लास में होना है इसलिए Entity से आप बच नहीं सकते ... और इसलिए बड़े कठिन तथ्य: आपको कुछ परिणाम की आवश्यकता नहीं है प्राथमिक कुंजी के लिए - अभी भी आपके पास Entity में @Id है ... हास्यास्पद सही है?
अर्नब दत्ता

210

मुझे इसका कुछ हल मिल गया है।

मैप्ड एंटिटीज़ (JPA 2.0) का उपयोग करना

JPA 2.0 का उपयोग करके एक देशी क्वेरी को POJO में मैप करना संभव नहीं है, यह केवल एक इकाई के साथ किया जा सकता है।

उदाहरण के लिए:

Query query = em.createNativeQuery("SELECT name,age FROM jedi_table", Jedi.class);
@SuppressWarnings("unchecked")
List<Jedi> items = (List<Jedi>) query.getResultList();

लेकिन इस मामले में, Jediएक मैप्ड इकाई वर्ग होना चाहिए।

यहां अनियंत्रित चेतावनी से बचने का एक विकल्प, एक नामित देशी क्वेरी का उपयोग करना होगा। तो अगर हम एक इकाई में देशी क्वेरी की घोषणा करते हैं

@NamedNativeQuery(
 name="jedisQry", 
 query = "SELECT name,age FROM jedis_table", 
 resultClass = Jedi.class)

फिर, हम बस कर सकते हैं:

TypedQuery<Jedi> query = em.createNamedQuery("jedisQry", Jedi.class);
List<Jedi> items = query.getResultList();

यह सुरक्षित है, लेकिन हम अभी भी मैप की गई इकाई का उपयोग करने के लिए प्रतिबंधित हैं।

मैनुअल मैपिंग

एक समाधान जो मैंने थोड़ा प्रयोग किया (जेपीए 2.1 के आने से पहले) एक पीओजेओ कंस्ट्रक्टर के खिलाफ थोड़ा प्रतिबिंब का उपयोग करके मैपिंग कर रहा था।

public static <T> T map(Class<T> type, Object[] tuple){
   List<Class<?>> tupleTypes = new ArrayList<>();
   for(Object field : tuple){
      tupleTypes.add(field.getClass());
   }
   try {
      Constructor<T> ctor = type.getConstructor(tupleTypes.toArray(new Class<?>[tuple.length]));
      return ctor.newInstance(tuple);
   } catch (Exception e) {
      throw new RuntimeException(e);
   }
}

यह विधि मूल रूप से टुपल ऐरे (मूल प्रश्नों द्वारा लौटाए गए) के रूप में लेती है और एक प्रदान किए गए POJO वर्ग के खिलाफ एक ऐसे निर्माता की तलाश करती है, जिसमें समान फ़ील्ड्स और समान प्रकार की संख्या हो।

तब हम सुविधाजनक तरीकों का उपयोग कर सकते हैं:

public static <T> List<T> map(Class<T> type, List<Object[]> records){
   List<T> result = new LinkedList<>();
   for(Object[] record : records){
      result.add(map(type, record));
   }
   return result;
}

public static <T> List<T> getResultList(Query query, Class<T> type){
  @SuppressWarnings("unchecked")
  List<Object[]> records = query.getResultList();
  return map(type, records);
}

और हम बस इस तकनीक का उपयोग इस प्रकार कर सकते हैं:

Query query = em.createNativeQuery("SELECT name,age FROM jedis_table");
List<Jedi> jedis = getResultList(query, Jedi.class);

JPA 2.1 @SqlResultSetMapping के साथ

JPA 2.1 के आगमन के साथ, हम समस्या को हल करने के लिए @SqlResultSetMapping एनोटेशन का उपयोग कर सकते हैं।

हमें किसी इकाई में कहीं भी परिणाम सेट मैपिंग घोषित करने की आवश्यकता है:

@SqlResultSetMapping(name="JediResult", classes = {
    @ConstructorResult(targetClass = Jedi.class, 
    columns = {@ColumnResult(name="name"), @ColumnResult(name="age")})
})

और फिर हम बस करते हैं:

Query query = em.createNativeQuery("SELECT name,age FROM jedis_table", "JediResult");
@SuppressWarnings("unchecked")
List<Jedi> samples = query.getResultList();

बेशक, इस मामले में Jediएक मैपेड इकाई होने की आवश्यकता नहीं है। यह एक नियमित पीओजेओ हो सकता है।

XML मैपिंग का उपयोग करना

मैं उन लोगों में से एक @SqlResultSetMappingहूं जो अपनी संस्थाओं में इन सभी सुंदर आक्रामक को जोड़ते हैं , और मैं विशेष रूप से संस्थाओं के भीतर नामित प्रश्नों की परिभाषा को नापसंद करता हूं, इसलिए वैकल्पिक रूप से मैं यह सब META-INF/orm.xmlफाइल में करता हूं :

<named-native-query name="GetAllJedi" result-set-mapping="JediMapping">
    <query>SELECT name,age FROM jedi_table</query>
</named-native-query>

<sql-result-set-mapping name="JediMapping">
        <constructor-result target-class="org.answer.model.Jedi">
            <column name="name" class="java.lang.String"/>
            <column name="age" class="java.lang.Integer"/>
        </constructor-result>
    </sql-result-set-mapping>

और वे सभी उपाय मुझे पता हैं। अंतिम दो आदर्श तरीके हैं यदि हम जेपीए 2.1 का उपयोग कर सकते हैं।


1
सिडेनोट: मैंने JPA2.1 निर्भरता के साथ सिर्फ JPA 2.0 दृष्टिकोण का उपयोग किया, और यह विफल रहा। तो शायद यह नीचे की ओर संगत नहीं है ...
सदस्य

1
"एक इकाई में कहीं" से आपका क्या मतलब है? मेरा पूजो एक जेपीए नहीं है, क्या मैं अपने POJO में @SqlResultSetMapping की घोषणा नहीं कर सकता? मुझे जेपीए 2.1 के समाधानों में दिलचस्पी है। कृपया थोड़ा और सटीक रहें।
अल्बोज़

3
@Alboz @SqlResultSetMappingको एक इकाई में रखा जाना चाहिए क्योंकि यही जेपीए मेटाडेटा को पढ़ने जा रहा है। आप उम्मीद नहीं कर सकते कि जेपीए आपके पीओजेओ का निरीक्षण करेगा। जिस इकाई में आप मैपिंग करते हैं वह अप्रासंगिक है, शायद वह जो आपके POJO परिणामों से अधिक संबंधित है। वैकल्पिक रूप से मैपिंग XML में पूरी तरह से असंबंधित इकाई के साथ युग्मन से बचने के लिए व्यक्त की जा सकती है।
एडविन डेलोरजो

1
क्या निर्माणकर्ता के लिए संभव है कि एक नेस्टेड क्लास का उपयोग करें?
क्रिस्मार्क्स

5
यदि @SqlResultSetMappingइसके साथ JPA 2.1 का उपयोग किया जा सकता है, तो यह ध्यान देने योग्य हो सकता है कि Jediवर्ग को एक ऑर्ग-आर्ग कंस्ट्रक्टर की आवश्यकता होगी और @ColumnResultएनोटेशन typeको रूपांतरण में जोड़े गए विशेषता की आवश्यकता हो सकती है, जिसका निहितार्थ नहीं हो सकता है (मुझे type = ZonedDateTime.classकुछ कॉलम जोड़ने की आवश्यकता है )।
ग्लेन

11

हां, JPA 2.1 के साथ यह आसान है। आपके पास बहुत उपयोगी एनोटेशन हैं। वे आपके जीवन को सरल बनाते हैं।

पहले अपनी मूल क्वेरी घोषित करें, फिर आपका परिणाम सेट मैपिंग (जो डेटाबेस द्वारा आपके POP पर लौटाए गए डेटा की मैपिंग को परिभाषित करता है)। संदर्भित करने के लिए अपने POJO वर्ग को लिखें (संक्षिप्तता के लिए यहां शामिल नहीं)। अंतिम लेकिन कम से कम: क्वेरी को कॉल करने के लिए DAO (उदाहरण के लिए) में एक विधि बनाएँ। यह मेरे लिए एक ड्रॉपवॉडर (1.0.0) ऐप में काम करता था।

पहले एक इकाई वर्ग में एक मूल प्रश्न घोषित करें:

@NamedNativeQuery (
name = "domain.io.MyClass.myQuery",
query = "Select a.colA, a.colB from Table a",
resultSetMapping = "mappinMyNativeQuery")   // must be the same name as in the SqlResultSetMapping declaration

नीचे आप परिणाम मानचित्रण घोषणा जोड़ सकते हैं:

@SqlResultSetMapping(
name = "mapppinNativeQuery",  // same as resultSetMapping above in NativeQuery
   classes = {
      @ConstructorResult( 
          targetClass = domain.io.MyMapping.class,
          columns = {
               @ColumnResult( name = "colA", type = Long.class),  
               @ColumnResult( name = "colB", type = String.class)
          }
      )
   } 
)

बाद में एक DAO में आप क्वेरी को संदर्भित कर सकते हैं

public List<domain.io.MyMapping> findAll() {
        return (namedQuery("domain.io.MyClass.myQuery").list());
    }

बस।


अच्छा जवाब, लेकिन मुझे लगता है कि आपने पहले @ColumnResult एनोटेशन के बाद एक कोष्ठक को याद किया है।
mwatzer

कोड में गलतियां हैं, लेकिन सही करना आसान है। उदाहरण के लिए: "resulSetMapping =" होना चाहिए "resultSetMapping ="
Zbyszek

3
मुझे एक और कड़वा सच दिखाई देता है: NamedNativeQuery & SqlResultSetMapping को एक @ वर्गीयता में होना है
अर्नब दत्ता

10

यदि आप उपयोग करते हैं Spring-jpa, तो यह उत्तर और इस प्रश्न का पूरक है। यदि कोई दोष है तो कृपया इसे सुधारें। मैंने मुख्य रूप से Object[]"व्यावहारिक रूप से मिलने की जरूरत के आधार पर एक पूजो के लिए मानचित्रण परिणाम" प्राप्त करने के लिए तीन विधियों का उपयोग किया है :

  1. विधि में निर्मित जेपीए पर्याप्त है।
  2. विधि में निर्मित जेपीए पर्याप्त नहीं है, लेकिन sqlइसके साथ एक अनुकूलित Entityपर्याप्त हैं।
  3. पूर्व 2 विफल रहे, और मुझे एक का उपयोग करना होगा nativeQuery। यहाँ उदाहरण हैं। पूजो की उम्मीद थी:

    public class Antistealingdto {
    
        private String secretKey;
    
        private Integer successRate;
    
        // GETTERs AND SETTERs
    
        public Antistealingdto(String secretKey, Integer successRate) {
            this.secretKey = secretKey;
            this.successRate = successRate;
        }
    }

विधि 1 : पूजो को इंटरफ़ेस में बदलें:

public interface Antistealingdto {
    String getSecretKey();
    Integer getSuccessRate();
}

और भंडार:

interface AntiStealingRepository extends CrudRepository<Antistealing, Long> {
    Antistealingdto findById(Long id);
}

विधि 2 : रिपोजिटरी:

@Query("select new AntistealingDTO(secretKey, successRate) from Antistealing where ....")
Antistealing whatevernamehere(conditions);

नोट: POJO कंस्ट्रक्टर का पैरामीटर अनुक्रम POJO परिभाषा और sql दोनों में समान होना चाहिए।

विधि 3 : एडविन डेलोरोज़ो के उत्तर में उदाहरण के रूप में उपयोग करें @SqlResultSetMappingऔर ।@NamedNativeQueryEntity

पहले दो तरीके कई-इन-मिडिल हैंडलर को कहेंगे, जैसे कि कस्टमाइज्ड कन्वर्टर्स। उदाहरण के लिए, इसे AntiStealingपरिभाषित करने secretKeyसे पहले, इसे परिभाषित करने के लिए एक कनवर्टर डाला जाता है। इसके परिणामस्वरूप पहले 2 तरीके बदले हुए वापस लौटेंगे secretKeyजो कि मैं नहीं चाहता। जबकि विधि 3 कनवर्टर को पार कर लेगा, और लौटाया secretKeyगया वही होगा जो संग्रहीत है (एक एन्क्रिप्ट किया गया)।


विधि 1 को वास्तव में स्प्रिंग की आवश्यकता नहीं है और शुद्ध हाइबरनेट के साथ काम करता है।
मार्टिन विनी

@MartinVysny हाँ, M1 JPQL है। किसी भी परियोजना को लागू करना चाहिए JPQL को इसका समर्थन करना चाहिए। इस तरह, शायद M2 का भी व्यापक रूप से समर्थन किया जाता है?
तिना

8

गैर-इकाई (जो कि बीन्स / पीओजेओ है) को परिणाम प्रदान करने के लिए अनवाप प्रक्रिया की जा सकती है। प्रक्रिया इस प्रकार है।

List<JobDTO> dtoList = entityManager.createNativeQuery(sql)
        .setParameter("userId", userId)
        .unwrap(org.hibernate.Query.class).setResultTransformer(Transformers.aliasToBean(JobDTO.class)).list();

उपयोग जेपीए-हाइबरनेट कार्यान्वयन के लिए है।


ध्यान दें कि JobDTOडिफ़ॉल्ट निर्माता होना चाहिए। या आप कार्यान्वयन के आधार पर अपने स्वयं के ट्रांसफार्मर को AliasToBeanResultTransformerलागू कर सकते हैं।
Lu55

4

एनोटेशन के बाद पहली घोषणा:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NativeQueryResultEntity {
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NativeQueryResultColumn {
    int index();
}

फिर अपने POJO को निम्नानुसार एनोटेट करें:

@NativeQueryResultEntity
public class ClassX {
    @NativeQueryResultColumn(index=0)
    private String a;

    @NativeQueryResultColumn(index=1)
    private String b;
}

फिर एनोटेशन प्रोसेसर लिखें:

public class NativeQueryResultsMapper {

    private static Logger log = LoggerFactory.getLogger(NativeQueryResultsMapper.class);

    public static <T> List<T> map(List<Object[]> objectArrayList, Class<T> genericType) {
        List<T> ret = new ArrayList<T>();
        List<Field> mappingFields = getNativeQueryResultColumnAnnotatedFields(genericType);
        try {
            for (Object[] objectArr : objectArrayList) {
                T t = genericType.newInstance();
                for (int i = 0; i < objectArr.length; i++) {
                    BeanUtils.setProperty(t, mappingFields.get(i).getName(), objectArr[i]);
                }
                ret.add(t);
            }
        } catch (InstantiationException ie) {
            log.debug("Cannot instantiate: ", ie);
            ret.clear();
        } catch (IllegalAccessException iae) {
            log.debug("Illegal access: ", iae);
            ret.clear();
        } catch (InvocationTargetException ite) {
            log.debug("Cannot invoke method: ", ite);
            ret.clear();
        }
        return ret;
    }

    // Get ordered list of fields
    private static <T> List<Field> getNativeQueryResultColumnAnnotatedFields(Class<T> genericType) {
        Field[] fields = genericType.getDeclaredFields();
        List<Field> orderedFields = Arrays.asList(new Field[fields.length]);
        for (int i = 0; i < fields.length; i++) {
            if (fields[i].isAnnotationPresent(NativeQueryResultColumn.class)) {
                NativeQueryResultColumn nqrc = fields[i].getAnnotation(NativeQueryResultColumn.class);
                orderedFields.set(nqrc.index(), fields[i]);
            }
        }
        return orderedFields;
    }
}

निम्नानुसार रूपरेखा का उपयोग करें:

String sql = "select a,b from x order by a";
Query q = entityManager.createNativeQuery(sql);

List<ClassX> results = NativeQueryResultsMapper.map(q.getResultList(), ClassX.class);

किस पैकेज BeanUtilsमें है?
हरीश

4

सबसे आसान तरीका है ताकि अनुमानों का उपयोग किया जा सके । यह क्वेरी परिणामों को सीधे इंटरफेस में मैप कर सकता है और SqlResultSetMapping का उपयोग करके लागू करना आसान है।

एक उदाहरण नीचे दिया गया है:

@Repository
public interface PeopleRepository extends JpaRepository<People, Long> {

    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
        "FROM people p INNER JOIN dream_people dp " +
        "ON p.id = dp.people_id " +
        "WHERE p.user_id = :userId " +
        "GROUP BY dp.people_id " +
        "ORDER BY p.name", nativeQuery = true)
    List<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId);

    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
        "FROM people p INNER JOIN dream_people dp " +
        "ON p.id = dp.people_id " +
        "WHERE p.user_id = :userId " +
        "GROUP BY dp.people_id " +
        "ORDER BY p.name", nativeQuery = true)
    Page<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId, Pageable pageable);

}



// Interface to which result is projected
public interface PeopleDTO {

    String getName();

    Long getCount();

}

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

इसके अलावा, यदि आप SELECT table.columnसंकेतन का उपयोग करते हैं, तो हमेशा उदाहरण से दिखाए गए नाम से उपनाम मिलान को परिभाषित करें।


1
देशी क्वेरी और अनुमान एक साथ अच्छी तरह से नहीं जाते हैं।
केविन रेव

1
मैं फील्ड मैपिंग को ठीक से काम नहीं कर पाया - अधिकांश मूल्य शून्य के रूप में वापस आते रहे
ayang

4

हाइबरनेट में आप आसानी से अपनी मूल क्वेरी को मैप करने के लिए इस कोड का उपयोग कर सकते हैं।

private List < Map < String, Object >> getNativeQueryResultInMap() {
String mapQueryStr = "SELECT * FROM AB_SERVICE three ";
Query query = em.createNativeQuery(mapQueryStr);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List < Map < String, Object >> result = query.getResultList();
for (Map map: result) {
    System.out.println("after request  ::: " + map);
}
return result;}

2

सीतनिद्रा में होना:

@Transactional(readOnly=true)
public void accessUser() {
EntityManager em = repo.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    org.hibernate.SQLQuery q = (org.hibernate.SQLQuery) session.createSQLQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u").addScalar("username", StringType.INSTANCE).addScalar("name", StringType.INSTANCE).addScalar("email", StringType.INSTANCE).addScalar("passe", StringType.INSTANCE).addScalar("loginType", IntegerType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(User2DTO.class));

    List<User2DTO> userList = q.list();
}

2

पुरानी शैली ResultSet का उपयोग कर

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = this.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    session.doWork(new Work() {
        @Override
        public void execute(Connection con) throws SQLException {
            try (PreparedStatement stmt = con.prepareStatement(
                    "SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")) {
                ResultSet rs = stmt.executeQuery();
                ResultSetMetaData rsmd = rs.getMetaData();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    System.out.print(rsmd.getColumnName(i) + " (" + rsmd.getColumnTypeName(i) + ") / ");
                }
                System.out.println("");
                while (rs.next()) {
                    System.out.println("Found username " + rs.getString("USERNAME") + " name " + rs.getString("NAME") + " email " + rs.getString("EMAIL") + " passe " + rs.getString("PASSE") + " email " + rs.getInt("LOGIN_TYPE"));
                }
            }
        }
    });
}

1

चूंकि अन्य लोगों ने पहले ही सभी संभावित समाधानों का उल्लेख किया है, इसलिए मैं अपना समाधान समाधान साझा कर रहा हूं।

साथ Postgres 9.4काम करते समय मेरी स्थिति में Jackson,

//Convert it to named native query.
List<String> list = em.createNativeQuery("select cast(array_to_json(array_agg(row_to_json(a))) as text) from myschema.actors a")
                   .getResultList();

List<ActorProxy> map = new ObjectMapper().readValue(list.get(0), new TypeReference<List<ActorProxy>>() {});

मुझे यकीन है कि आप अन्य डेटाबेस के लिए समान पा सकते हैं।

इसके अलावा FYI करें, JPA 2.0 मूल क्वेरी के नक्शे के रूप में परिणाम है


1

यकीन नहीं होता कि यह यहाँ फिट बैठता है, लेकिन मेरे पास इसी तरह का सवाल था और मेरे लिए सरल समाधान / उदाहरण निम्नलिखित है:

private EntityManager entityManager;
...
    final String sql = " SELECT * FROM STORE "; // select from the table STORE
    final Query sqlQuery = entityManager.createNativeQuery(sql, Store.class);

    @SuppressWarnings("unchecked")
    List<Store> results = (List<Store>) sqlQuery.getResultList();

मेरे मामले में मुझे कहीं और स्ट्रिंग्स में परिभाषित एसक्यूएल भागों का उपयोग करना था, इसलिए मैं सिर्फ NamedNativeQuery का उपयोग नहीं कर सका।


जैसे ही हम वापसी इकाई। कुछ भी आकर्षक नहीं। समस्या तब होती है जब आप परिणाम को अप्रबंधित POJO में मैप करने का प्रयास करते हैं।
ओल्गुन काया

1

पुरानी शैली का उपयोग कर Resultset

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = this.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    session.doWork(new Work() {
        @Override
        public void execute(Connection con) throws SQLException {
            try (PreparedStatement stmt = con.prepareStatement(
                    "SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")) {
                ResultSet rs = stmt.executeQuery();
                ResultSetMetaData rsmd = rs.getMetaData();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    System.out.print(rsmd.getColumnName(i) + " (" + rsmd.getColumnTypeName(i) + ") / ");
                }
                System.out.println("");
                while (rs.next()) {
                    System.out.println("Found username " + rs.getString("USERNAME") + " name " + rs.getString("NAME") + " email " + rs.getString("EMAIL") + " passe " + rs.getString("PASSE") + " email " + rs.getInt("LOGIN_TYPE"));
                }
            }
        }
    });
}

1

हमने निम्नलिखित तरीके से समस्या का समाधान किया है:

   //Add actual table name here in Query
    final String sqlQuery = "Select a.* from ACTORS a"
    // add your entity manager here 
    Query query = entityManager.createNativeQuery(sqlQuery,Actors.class);
    //List contains the mapped entity data.
    List<Actors> list = (List<Actors>) query.getResultList();

0

जटिल SqlResultSMMapping का उपयोग किए बिना मूल क्वेरी से परिणाम प्राप्त करने के लिए छद्म इकाई के रूप में पीओजेओ का उपयोग करने के लिए नीचे दिए गए उदाहरण देखें। बस आपके POJO में दो एनोटेशन, एक नंगे @Eality और एक डमी @Id की आवश्यकता है। @Id को अपनी पसंद के किसी भी क्षेत्र में उपयोग किया जा सकता है, @Id फ़ील्ड में डुप्लिकेट कुंजियाँ हो सकती हैं, लेकिन शून्य मान नहीं।

चूंकि @Eality किसी भी भौतिक तालिका में मैप नहीं करता है, इसलिए इस POJO को एक छद्म इकाई कहा जाता है।

पर्यावरण: ग्रहण 2.5.0-RC1, jpa-2.1.0, mysql-कनेक्टर-जावा-5.1.14

आप यहाँ पूरा मावेन प्रोजेक्ट डाउनलोड कर सकते हैं

मूल प्रश्न mysql के नमूना कर्मचारियों पर आधारित है db http://dev.mysql.com/doc/employee/en/employees-installation.html

persistence.xml

<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="jpa-mysql" transaction-type="RESOURCE_LOCAL">
    <class>org.moonwave.jpa.model.pojo.Employee</class>
    <properties>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/employees" />
        <property name="javax.persistence.jdbc.user" value="user" />
        <property name="javax.persistence.jdbc.password" value="***" />
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
    </properties>
</persistence-unit>

Employee.java

package org.moonwave.jpa.model.pojo;

@Entity
public class Employee {

@Id
protected Long empNo;

protected String firstName;
protected String lastName;
protected String title;

public Long getEmpNo() {
    return empNo;
}
public void setEmpNo(Long empNo) {
    this.empNo = empNo;
}
public String getFirstName() {
    return firstName;
}
public void setFirstName(String firstName) {
    this.firstName = firstName;
}
public String getLastName() {
    return lastName;
}
public void setLastName(String lastName) {
    this.lastName = lastName;
}   
public String getTitle() {
    return title;
}
public void setTitle(String title) {
    this.title = title;
}
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("empNo: ").append(empNo);
    sb.append(", firstName: ").append(firstName);
    sb.append(", lastName: ").append(lastName);
    sb.append(", title: ").append(title);
    return sb.toString();
}
}

EmployeeNativeQuery.java

public class EmployeeNativeQuery {
private EntityManager em;
private EntityManagerFactory emf;

public void setUp() throws Exception {
    emf=Persistence.createEntityManagerFactory("jpa-mysql");
    em=emf.createEntityManager();
}
public void tearDown()throws Exception {
    em.close();
    emf.close();
}

@SuppressWarnings("unchecked")
public void query() {
    Query query = em.createNativeQuery("select e.emp_no as empNo, e.first_name as firstName, e.last_name as lastName," + 
            "t.title from employees e join titles t on e.emp_no = t.emp_no", Employee.class);
    query.setMaxResults(30);
    List<Employee> list = (List<Employee>) query.getResultList();
    int i = 0;
    for (Object emp : list) {
        System.out.println(++i + ": " + emp.toString());
    }
}

public static void main( String[] args ) {
    EmployeeNativeQuery test = new EmployeeNativeQuery();
    try {
        test.setUp();
        test.query();
        test.tearDown();
    } catch (Exception e) {
        System.out.println(e);
    }
}
}

1
चूंकि आपका listहै, कथित तौर पर, आपकी सूची Employee, प्रत्येक प्रकार के लिए आपके प्रत्येक लूप को क्यों है Object? यदि आप अपना प्रत्येक लूप लिखते हैं for(Employee emp : list)तो आपको पता चलता है कि आपका उत्तर गलत है और आपकी सूची की सामग्री कर्मचारी नहीं हैं और यह कि आपके द्वारा दी गई चेतावनी का उद्देश्य आपको इस संभावित गलती के बारे में सचेत करना था।
एडविन दलेरजो

@SuppressWarnings ("अनियंत्रित") का उपयोग List<Employee> list = (List<Employee>) query.getResultList();चेंज के for (Object emp : list)लिए चेतावनी को दबाने के लिए for (Employee emp : list)बेहतर है, लेकिन कोई त्रुटि नहीं है यदि Object empसूची के रूप में रखा जाए तो इसका एक उदाहरण है List<Employee>। मैंने git प्रोजेक्ट में कोड को बदल दिया है, लेकिन अपनी टिप्पणी को मूल पोस्ट के लिए प्रासंगिक रखने के लिए यहां नहीं है
जोनाथन एल

समस्या यह है कि आपकी क्वेरी रोजगार की सूची में वापस नहीं आती है, लेकिन वस्तुओं की एक सरणी। आपकी दबी हुई चेतावनी छिपी हुई है। उस क्षण में जब आप उनमें से किसी को कर्मचारी में बदलने की कोशिश करते हैं, तो आपको एक त्रुटि, एक कास्ट अपवाद मिलेगा।
एडविन डेलोरोज़ो

देखो Query query = em.createNativeQuery("select * ...", Employee.class);और हठ। xml, देशी क्वेरी कर्मचारी की सूची लौटाती है। मैंने अभी प्रोजेक्ट w / o समस्या की जाँच की और चलाया। यदि आप mysql नमूना कर्मचारियों को स्थानीय रूप से db सेटअप करते हैं, तो आपको इस परियोजना को चलाने में सक्षम होना चाहिए
जोनाथन एल

ओह, मैं देख रहा हूं कि अब आपका क्या मतलब है। लेकिन उस स्थिति में आपका उत्तर प्रश्न को संतुष्ट नहीं करता है, क्योंकि यह एक नियमित POJO को लक्ष्य वस्तु के रूप में उपयोग करने के बारे में था, और आपका उत्तर वह उपयोग Employeeकर रहा है जो मुझे लगता है कि एक इकाई है। है ना?
एडविन डेलोरोज़ो

0

यदि आप स्प्रिंग का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं org.springframework.jdbc.core.RowMapper

यहाँ एक उदाहरण है:

public List query(String objectType, String namedQuery)
{
  String rowMapper = objectType + "RowMapper";
  // then by reflection you can instantiate and use. The RowMapper classes need to follow the naming specific convention to follow such implementation.
} 

0

सीतनिद्रा में होना:

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = repo.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    org.hibernate.SQLQuery q = (org.hibernate.SQLQuery) session.createSQLQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")
        .addScalar("username", StringType.INSTANCE).addScalar("name", StringType.INSTANCE)
        .addScalar("email", StringType.INSTANCE).addScalar("passe", StringType.INSTANCE)
        .addScalar("loginType", IntegerType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(User2DTO.class));

    List<User2DTO> userList = q.list();
}

-1

SQL क्वेरी को POJO वर्ग संग्रह में परिवर्तित करने का सरल तरीका,

Query query = getCurrentSession().createSQLQuery(sqlQuery).addEntity(Actors.class);
List<Actors> list = (List<Actors>) query.list();
return list;

-1

आपको एक निर्माता के साथ डीटीओ की आवश्यकता है:

public class User2DTO implements Serializable {

    /** pode ser email ou id do Google comecando com G ou F para Facebook */
    private String username;

    private String password;

    private String email;

    private String name;

    private Integer loginType;

    public User2DTO(Object...fields) {
        super();
        this.username = (String) fields[0];
        this.name = (String) fields[1];
        this.email = (String) fields[2];
        this.password = (String) fields[3];
        this.loginType = (Integer) fields[4];
    }

और इसे कॉल करें:

EntityManager em = repo.getEntityManager();
        Query q = em.createNativeQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u");
        List<Object[]> objList = q.getResultList();
        List<User2DTO> ooBj = objList.stream().map(User2DTO::new).collect(Collectors.toList());

एक नया कॉलम जोड़ें और कोड टूट जाएगा।
डिश

-2

का उपयोग करें DTO Design Pattern। में इसका उपयोग किया गया था EJB 2.0। इकाई कंटेनर का प्रबंधन किया गया था। DTO Design Patternइस समस्या को हल करने के लिए उपयोग किया जाता है। लेकिन, इसका उपयोग अब हो सकता है, जब एप्लिकेशन विकसित Server Sideऔर Client Sideअलग-अलग हो। DTOका उपयोग तब किया जाता है जब Server sideवह Entityएनोटेशन के साथ पास / वापसी नहीं करना चाहता Client Side

डीटीओ उदाहरण:

PersonEntity.java

@Entity
public class PersonEntity {
    @Id
    private String id;
    private String address;

    public PersonEntity(){

    }
    public PersonEntity(String id, String address) {
        this.id = id;
        this.address = address;
    }
    //getter and setter

}

PersonDTO.java

public class PersonDTO {
    private String id;
    private String address;

    public PersonDTO() {
    }
    public PersonDTO(String id, String address) {
        this.id = id;
        this.address = address;
    }

    //getter and setter 
}

DTOBuilder.java

public class DTOBuilder() {
    public static PersonDTO buildPersonDTO(PersonEntity person) {
        return new PersonDTO(person.getId(). person.getAddress());
    }
}

EntityBuilder.java <- इसकी जरूरत है

public class EntityBuilder() {
    public static PersonEntity buildPersonEntity(PersonDTO person) {
        return new PersonEntity(person.getId(). person.getAddress());
    }
}

4
जवाब के लिए धन्यवाद। मुझे डीटीओ पैटर्न की आवश्यकता नहीं है। मेरी आवश्यकता ग्राहक से एनोटेशन विवरण को छिपाने की नहीं है। इसलिए मुझे अपने ऐप में एक और पीओजेओ बनाने की आवश्यकता नहीं है। मेरी आवश्यकता यह है कि परिणाम को qa pojo पर सेट किया जाए जो कि JAVA इकाई नहीं है, बल्कि सरल POJO वर्ग है, जिसके परिणाम फ़ील्ड के समान स्तंभ हैं।
गुंजन शाह
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.