<টাইপ> তালিকাতে হাইবারনেট কোয়েরি.লিস্ট () কে কাস্ট করার "যথাযথ" উপায় কী?


84

আমি হাইবারনেট সহ একজন নবাগত এবং নির্দিষ্ট ফিল্টারটির সাথে মেলে এমন সামগ্রীর তালিকা ফিরিয়ে দেওয়ার জন্য আমি একটি সহজ পদ্ধতি লিখছি। List<Foo>একটি প্রাকৃতিক রিটার্ন টাইপ মনে হয়েছিল।

আমি যাই করুক না কেন, আমি কুশলী নিয়োগ না করে সংকলকটিকে খুশি মনে করতে পারি না @SuppressWarnings

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class Foo {

    public Session acquireSession() {
        // All DB opening, connection etc. removed,
        // since the problem is in compilation, not at runtime.
        return null;
    }

    @SuppressWarnings("unchecked") /* <----- */

    public List<Foo> activeObjects() {
        Session s = acquireSession();
        Query   q = s.createQuery("from foo where active");
        return (List<Foo>) q.list();
    }
}

আমি এ থেকে মুক্তি পেতে চাইSuppressWarnings । তবে আমি যদি তা করি তবে আমি সতর্কতাটি পেয়েছি

Warning: Unchecked cast from List to List<Foo>

(আমি এটিকে উপেক্ষা করতে পারি, তবে আমি এটি প্রথম স্থানে না পেতে চাই) এবং যদি আমি .list()ফিরে আসার অনুসারে জেনেরিকটি সরিয়ে ফেলি তবে আমি সতর্কতা পেয়ে যাব

Warning: List is a raw type. References to generic type List<E>
should be parameterized.

আমি লক্ষ্য করেছি যে org.hibernate.mapping এটি একটি ঘোষণা করে List; তবে এটি পুরোপুরি ভিন্ন ধরণের - Queryএকটি java.util.List, কাঁচা প্রকার হিসাবে প্রদান করে। আমি এটিকে অদ্ভুত বলে মনে করি যে সাম্প্রতিক একটি হাইবারনেট (৪.০.x) প্যারামিটারাইজড ধরণের প্রয়োগ করে না, তাই আমার সন্দেহ হয় যে এটির পরিবর্তে আমি কিছু ভুল করছি।

এটি কাস্টিং হাইবারনেট ফলাফলের মতো দেখতে অবজেক্টগুলির তালিকার মতো , তবে এখানে আমার কোনও "হার্ড" ত্রুটি নেই (সিস্টেমটি ফু টাইপ জানে এবং আমি একটি এসকিউএলকিউরি ব্যবহার করি না তবে একটি সোজা অনুসন্ধান) ery তাই আনন্দ নেই।

আমিও দিকে তাকিয়ে আছে হাইবারনেট ক্লাস কাস্ট ব্যতিক্রম যেহেতু এটি প্রতিশ্রুতি লাগছিল, কিন্তু তারপর আমি বুঝতে পারি যে আমি না আসলে কোনো পেতে Exception, একটি কোডিং শৈলী যদি আপনি হবে - ... আমার সমস্যা শুধু একটি সতর্কবার্তা যে।

Jboss.org, হাইবারনেট ম্যানুয়াল এবং বেশ কিছু টিউটোরিয়াল উপর ডকুমেন্টেশন মধ্যে বিষয় আবরণ বলে মনে হচ্ছে না এই ধরনের (আমি সঠিক স্থানগুলি অনুসন্ধান করা হয়নি বা?) বিস্তারিত। যখন তারা বিশদে প্রবেশ করায় তারা অন-দ্য ফ্লাই কাস্টিং ব্যবহার করে - এবং এটি টিউটোরিয়ালগুলিতে যা অফিসিয়াল jboss.org সাইটে ছিল না, তাই আমি কিছুটা সতর্ক।

একবার সংকলিত কোডটি কোনও আপাত সমস্যা ছাড়াই চলে ... যা আমি জানি ... এখনও; এবং ফলাফলগুলি প্রত্যাশিত ফলাফল।

তো: আমি কি এই সঠিকভাবে করছি? আমি কি স্পষ্ট কিছু মিস করছি? কোনও "অফিসিয়াল" বা "প্রস্তাবিত" করার উপায় আছে ?

উত্তর:


101

সংক্ষিপ্ত উত্তর @SuppressWarningsহ'ল সঠিক উপায়।

দীর্ঘ উত্তর, হাইবারনেট পদ্ধতি Listথেকে একটি কাঁচা ফেরত Query.list, এখানে দেখুন । এটি হাইবারনেটযুক্ত কোনও বাগ বা সমাধান করা যেতে পারে এমন কোনও সমস্যা নয় , ক্যোয়ারী দ্বারা ফেরানো টাইপটি সংকলনের সময় জানা যায় না

সুতরাং আপনি যখন লিখুন

final List<MyObject> list = query.list();

আপনি থেকে একটি অনিরাপদ ঢালাই করছেন Listকরার List<MyObject>- এই এড়িয়ে চলা যাবে না।

কাস্টটি নিরাপদে চালিয়ে যাওয়ার কোনও উপায় নেই List কারণ এতে যে কোনও কিছু থাকতে পারে।

ত্রুটি সরিয়ে দেওয়ার একমাত্র উপায় হ'ল আরও কুৎসিত

final List<MyObject> list = new LinkedList<>();
for(final Object o : query.list()) {
    list.add((MyObject)o);
}

4
আমি আরও ভাল উত্তর আসবে এই আশায় আমি আপনার উত্তরটিকে উচ্চতর করতে যাচ্ছি। পরিবর্তে আমি ব্রুস এক্কেল (জাভাতে চিন্তাভাবনা) এবং রবার্ট সেডজউইক - দ্য সেজউইক উভয়ই "কুৎসিত castাল" হিসাবে অভিহিত হয়েছি । আমি স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / 509076/ …ও পেয়েছি । দীর্ঘশ্বাস.
এলসার্নি

6
আমি আপনার ব্যবহারের স্টাইলটি পছন্দ করিfinal
পাভেল

9
হাইবারনেট বলছি ধরনের সঙ্গে একটি আর্গুমেন্ট যুক্ত করে থাকেন Class<?>মধ্যে list(), সমস্যা সমাধান করা যেতে পারে। এরকম কুরুচিপূর্ণ এপিআই ব্যবহার করা লজ্জাজনক।
বিন ওয়াং

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

4
@ পেটিপ্যাবপ্রো যদিও আমি একমত যে কাঁচা টাইপগুলি এড়ানো উচিত, আমি একমত নই যে কোনও প্রশ্নের ফলাফলকে একটি হিসাবে বিবেচনা করা উচিত List<Object>। ফলাফলগুলি প্রত্যাশিত ধরণে ফেলে দেওয়া উচিত এবং ইউনিট পরীক্ষাগুলি যুক্ত করা উচিত যাতে নিশ্চিত হয়ে যায় যে ক্যোয়ারী সঠিক ফলাফল দেয়। " পরে কোডে " ক্যোয়ারীগুলি চালু করার সাথে ত্রুটি থাকা অগ্রহণযোগ্য । আপনার উদাহরণ কোডিং অনুশীলনের বিরুদ্ধে একটি যুক্তি যা একবিংশ শতাব্দীতে অ্যানথেমা হওয়া উচিত। এটি হ'ল, আমি প্রস্তাব দেব, এটি কখনই গ্রহণযোগ্য নয়List<Object>
বরিস স্পাইডার

26

রেজোলিউশনের পরিবর্তে টাইপকুইডারি ব্যবহার করা। সত্তা ম্যানেজার থেকে কোনও ক্যোয়ারী তৈরি করার পরিবর্তে এটিকে এভাবে কল করুন:

TypedQuery<[YourClass]> query = entityManager.createQuery("[your sql]", [YourClass].class);
List<[YourClass]> list = query.getResultList(); //no type warning

এটি নামযুক্ত ক্যোয়ারী, নেটিভ নামযুক্ত প্রশ্নের জন্যও একই কাজ করে etc. ইত্যাদি সম্পর্কিত পদ্ধতিগুলির ভ্যানিলা কোয়েরিটি ফেরত দেওয়ার মতো একই নাম রয়েছে। যখনই আপনি রিটার্নের ধরণটি জানেন তখন কেবল কোয়েরির পরিবর্তে এটি ব্যবহার করুন।


4
পার্শ্ব নোট হিসাবে, আপনি ইনলাইন তৈরি করছেন এমন খাঁটি দেশীয় প্রশ্নের জন্য এটি কাজ করে না। ফিরে ক্যোয়ারী শুধুমাত্র কখনও একটি কোয়েরি, না একটি typedquery :( হয়
Taugenichts

এখন, ত্রুটি বার্তাটি চলে গেছে এবং ফলস্বরূপ তালিকাটি অবজেক্ট অবজেক্টের পরিবর্তে প্রকৃত অবজেক্ট ব্যবহার করে .. দুর্দান্ত উত্তর!
জোহানেস

এটি হাইবারনেট 5.0 এ প্রকাশিত হয়েছে বলে মনে হয়। আমি এটি 4.3.11 এ দেখছি না তবে নীচের নিবন্ধটি 5.3 উল্লেখ করে। wiki.openbravo.com/wiki/… আমি জানুয়ারী 2014 এর স্ট্যাকওভারফ্লো পোস্টটি এটি উল্লেখ করছি: stackoverflow.com/a/21354639/854342
কার্টিস ইয়ালোপ

এটি হাইবারনেট-জেপা -২.০-এপিআই-র অংশ। আপনি এটি হাইবারনেট ৪.৩ দিয়ে ব্যবহার করতে পারেন, কারণ আমি বর্তমানে এটি হাইবারনেট ৪.৩ এ ব্যবহার করছি।
টগজিনিটস

6

আপনি এই জাতীয় কাজের সাথে সংকলক সতর্কতা এড়াতে পারেন:

List<?> resultRaw = query.list();
List<MyObj> result = new ArrayList<MyObj>(resultRaw.size());
for (Object o : resultRaw) {
    result.add((MyObj) o);
}

তবে এই কোডটিতে কিছু সমস্যা রয়েছে:

  • অতিমাত্রায় অ্যারেলিস্ট তৈরি করেছে
  • কোয়েরি থেকে সমস্ত উপাদানের উপর অপ্রয়োজনীয় লুপ ফিরে এসেছে
  • দীর্ঘ কোড।

এবং পার্থক্যটি কেবল প্রসাধনী, সুতরাং এই জাতীয় কাজের ব্যবহারটি আমার মতে - অর্থহীন।

আপনাকে এই সতর্কতাগুলির সাথে বাঁচতে হবে বা তাদের দমন করতে হবে।


4
আমি অর্থহীনতার সাথে একমত আমি দমন করব, এমনকি যদি এটি আমার দানার বিরুদ্ধে যায়। সব একই ধন্যবাদ, এবং +1।
এলসার্নি

4
> আপনাকে এই সতর্কতাগুলির সাথে বাঁচতে হবে বা তাদের দমন করতে হবে। ভুল যে সতর্কবার্তাগুলি ভুল তা দমন করা সর্বদা ভাল, বা আপনি অসমর্থিত ভুল সতর্কতার স্প্যামে সঠিক সতর্কতাটি মিস করতে পারেন
SpongeBob

6

আপনার প্রশ্নের উত্তর দেওয়ার জন্য, এটি করার কোনও "যথাযথ উপায়" নেই। এখন যদি এটি আপনাকে সতর্ক করে দেয় যা কেবল বিরক্ত হয় তবে এর বিস্তার এড়ানোর সর্বোত্তম উপায় হ'ল Query.list()পদ্ধতিটি ডিএওতে আবৃত করা:

public class MyDAO {

    @SuppressWarnings("unchecked")
    public static <T> List<T> list(Query q){
        return q.list();
    }
}

এইভাবে আপনি @SuppressWarnings("unchecked")কেবল একবার ব্যবহার করতে পারবেন ।


স্ট্যাক ওভারফ্লোতে স্বাগতম ! যাইহোক, ট্যুর
এস

3

আমার পক্ষে সেই কাজটি কেবল একজন আইট্রেটারের সাথে ছিল।

Iterator iterator= query.list().iterator();
Destination dest;
ArrayList<Destination> destinations= new ArrayList<>();
Iterator iterator= query.list().iterator();
    while(iterator.hasNext()){
        Object[] tuple= (Object[]) iterator.next();
        dest= new Destination();
        dest.setId((String)tuple[0]);
        dest.setName((String)tuple[1]);
        dest.setLat((String)tuple[2]);
        dest.setLng((String)tuple[3]);
        destinations.add(dest);
    }

আমি খুঁজে পাওয়া অন্যান্য পদ্ধতিগুলির সাথে আমার সমস্যা ছড়িয়ে পড়েছিল


"কাস্ট সমস্যা" কি? আমি সবসময় কেবল সরাসরি তালিকাটি সরাসরি কাস্ট করেছি, উপরের আরও সংক্ষিপ্ত বা নিরাপদ কীভাবে?
জিওভানি বোট্টা

আমি সরাসরি কাস্ট করতে পারি না। কাস্ট সমস্যা ছিল কারণ এটি অবজেক্ট থেকে গন্তব্যে কাস্ট করতে পারেনি
পোপা আন্ড্রেই

আপনি জানেন হাইবারনেট ঠিক আপনার জন্য একটি তৈরি করতে পারে Destinstion? select newবাক্য গঠন ব্যবহার করে । এটি অবশ্যই সঠিক পদ্ধতি নয়।
বোরিস দ্য স্পাইডার

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

3
List<Person> list = new ArrayList<Person>();
Criteria criteria = this.getSessionFactory().getCurrentSession().createCriteria(Person.class);
for (final Object o : criteria.list()) {
    list.add((Person) o);
}

হ্যাঁ, এটি মূলত বোরিসের প্রস্তাবিত একই 'কদর্যতা', লুপের মধ্যে একটি কাস্ট সহ।
এলসার্নি

2

আপনি এর মতো রেজাল্ট ট্রান্সফর্মার ব্যবহার করেন:

public List<Foo> activeObjects() {
    Session s = acquireSession();
    Query   q = s.createQuery("from foo where active");
    q.setResultTransformer(Transformers.aliasToBean(Foo.class));
    return (List<Foo>) q.list();
}

4
আমি এখন এটি পরীক্ষা করতে পারি না, তবে ... এই কী পরিবর্তন হয়? qএখনও একটি Queryএবং তাই q.list()এখনও একটি কাঁচা java.util.Listটাইপ। কাস্টটি তখনও চেক করা হয়নি; অভ্যন্তরীণভাবে অবজেক্টের ধরন পরিবর্তিত হওয়ার কোনও লাভ নেই ...
এলসার্নি

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

from foo where activeহয় না একটি নেটিভ জিজ্ঞাস্য। সুতরাং ফলাফল ট্রান্সফরমারের দরকার নেই, কারণ ডিফল্ট ম্যাপিং যথেষ্ট হবে। প্রশ্নটি POJO ক্ষেত্রগুলি ingালাইয়ের বিষয়ে নয়, ফলাফল অবজেক্টটি ingালাইয়ের বিষয়ে। ফলাফল ট্রান্সফর্মার এখানে সাহায্য করবে না।
টোবিয়াস লিফকে 11

0

হাইবারনেট ট্রান্সফর্মারগুলি ব্যবহার করার সঠিক উপায় হ'ল:

public class StudentDTO {
private String studentName;
private String courseDescription;

public StudentDTO() { }  
...
} 

List resultWithAliasedBean = s.createSQLQuery(
"SELECT st.name as studentName, co.description as courseDescription " +
"FROM Enrolment e " +
"INNER JOIN Student st on e.studentId=st.studentId " +
"INNER JOIN Course co on e.courseCode=co.courseCode")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();

StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);

থ্রোগথ অবজেক্টটি [te ট্রান্সফর্মার ব্যবহার সম্পর্কে বিস্তারিত তথ্য আপনি এখানে পাবেন: এইচকিউএল এবং এসকিউএল জন্য ট্রান্সফরমার

আপনি যদি আরও সাধারণ সমাধানের সন্ধান করে থাকেন তবে আপনি বাক্স-মানচিত্র-ট্রান্সফরমার ব্যবহার করতে পারেন:

List iter = s.createQuery(
"select e.student.name as studentName," +
"       e.course.description as courseDescription" +
"from   Enrolment as e")
.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP )
.iterate();

String name = (Map)(iter.next()).get("studentName");

প্রশ্ন ফলাফল রূপান্তর সম্পর্কে ছিল না। এটি Queryফলাফল কাস্টিং সম্পর্কে ছিল - যা এখনও আপনার উদাহরণে প্রয়োজন। এবং আপনার উদাহরণটির মূলটির সাথে কোনও সম্পর্ক নেই from foo where active
টোবিয়াস লিফকে 11

0

শুধু ট্রান্সফর্মার ব্যবহার করে এটি আমার পক্ষে কাজ করে না আমি টাইপ কাস্ট ব্যতিক্রম পাচ্ছি।

sqlQuery.setResultTransformer(Transformers.aliasToBean(MYEngityName.class)) কাজ করিনি কারণ আমি ফিরতি তালিকার উপাদানটিতে অবজেক্টের অ্যারে পেয়েছি স্থির MYEngityName তালিকার উপাদান নয়।

আমি যখন নিম্নলিখিত পরিবর্তনগুলি করি তখন এটি আমার জন্য কাজ করে যখন আমি sqlQuery.addScalar(-)প্রতিটি নির্বাচিত কলাম এবং এর ধরণ যুক্ত করি এবং নির্দিষ্ট স্ট্রিং টাইপ কলামের জন্য আমরা এর ধরণের মানচিত্র রাখি না। পছন্দaddScalar("langCode");

এবং আমি MYEngityName NextEnity এর সাথে যোগ দিয়েছি আমরা কেবল select *ক্যোয়ারিতেই তা করতে পারি না এটি রিটার্ন তালিকায় অবজেক্টের অ্যারে দেবে।

কোড নমুনার নীচে:

session = ht.getSessionFactory().openSession();
                String sql = new StringBuffer("Select txnId,nft.mId,count,retryReason,langCode FROM  MYEngityName nft INNER JOIN NextEntity m on nft.mId  =  m.id where nft.txnId < ").append(lastTxnId)
                       .append(StringUtils.isNotBlank(regionalCountryOfService)? " And  m.countryOfService in ( "+ regionalCountryOfService +" )" :"")
                       .append(" order by nft.txnId desc").toString();
                SQLQuery sqlQuery = session.createSQLQuery(sql);
                sqlQuery.setResultTransformer(Transformers.aliasToBean(MYEngityName.class));
                sqlQuery.addScalar("txnId",Hibernate.LONG)
                        .addScalar("merchantId",Hibernate.INTEGER)
                        .addScalar("count",Hibernate.BYTE)
                        .addScalar("retryReason")
                        .addScalar("langCode");
                sqlQuery.setMaxResults(maxLimit);
                return sqlQuery.list();

এটি কিছু সাহায্য করতে পারে। এইভাবে আমার জন্য কাজ।


-1

আমি এখানে সেরা সমাধানটি পেয়েছি , এই সমস্যাটির মূলটি হ'ল অ্যাডএনটিটি পদ্ধতি

public static void testSimpleSQL() {
    final Session session = sessionFactory.openSession();
    SQLQuery q = session.createSQLQuery("select * from ENTITY");
    q.addEntity(Entity.class);
    List<Entity> entities = q.list();
    for (Entity entity : entities) {
        System.out.println(entity);
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.