Hibernate Query.list ()를 List로 캐스팅하는“적절한”방법은 무엇입니까??
저는 Hibernate의 다음과 같은 특정 필터와 일치하는 개체 목록을 반환하는 간단한 방법을 작성하고 있습니다. List<Foo>
자연스러운 유형 반환처럼 보였습니다.
내가 무엇을하든 추악한 .NET을 사용하지 않는 한 컴파일러를 행복하게 만들 수 없습니다 @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
됩니다. 최근 Hibernate (4.0.x)가 매개 변수화 된 유형을 구현하지 않는 것이 이상하다는 것을 알기 때문에 대신 내가 뭔가 잘못하고 있다는 생각합니다.
Cast Hibernate 결과 와 매우 유사 하지만 여기에는 "하드"오류가 없습니다 (시스템은 Foo 유형을 알고있는 SQLQuery가 아니라는 쿼리를 사용하고 있습니다). 그래서 기쁨이 없습니다.
또한 나는 유망 해 보였기 때문에 최대 절전 모드 클래스 캐스트 예외 을 보았지만 실제로 는 아무것도 얻지 못한다 는 것을 깨달았습니다 Exception
... 내 문제는 경고의 문제입니다 - 당신이 원한다면 코딩 스타일.
jboss.org에 대한 문서, Hibernate 매뉴얼 및 검색 튜토리얼이 그 주제 를 그렇게 자세하게 다루지 않는 것 (또는 올바른 위치에서 발생하지 않습니까?). 세부 사항을 입력 할 때, 그들이 즉석 캐스팅을 사용합니다. 그리고 이것은 공식 jboss.org 사이트에 없었던 튜토리얼에 대한 것 약간 조심합니다.
일단 실행 된 코드는 명백한 문제 없이 실행됩니다 ... 내가 아는 ... 아직; 결과는 예상되는 것입니다.
그래서 :이 일을 제대로하고 있습니까? 나는 명백한 것을 놓치고 있습니까? "공식"또는 "권장" 방법이 있습니까?
짧은 대답 이 올바른 @SuppressWarnings
방법입니다.
긴 대답, Hibernate는 메서드 List
에서 원시 를 반환합니다 . 여기를Query.list
참조 하십시오 . 이것은 Hibernate의 버그 나 수있는 것이 아닙니다 . 에 의해 반환 쿼리 된 유형 은 컴파일 타임에 알려지지 않습니다 .
따라서 당신이 쓸 때
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);
}
해결 방법은 대신 TypedQuery를 사용하는 것입니다. EntityManager에서 쿼리를 만들 때 대신 다음과 같이 호출합니다.
TypedQuery<[YourClass]> query = entityManager.createQuery("[your sql]", [YourClass].class);
List<[YourClass]> list = query.getResultList(); //no type warning
이것은 또한 명명 된 쿼리, 동일하게 작동합니다. 해당 메소드는 바닐라 쿼리를 반환하는 것과 동일한 이름을 갖습니다. 반환 유형을 알 때마다 쿼리 대신 사용하십시오.
다음과 같은 해결 방법으로 컴파일러 경고를 피할 수 있습니다.
List<?> resultRaw = query.list();
List<MyObj> result = new ArrayList<MyObj>(resultRaw.size());
for (Object o : resultRaw) {
result.add((MyObj) o);
}
그러나이 코드에는 몇 가지 문제가 있습니다.
- 불필요한 ArrayList 생성
- 쿼리에서 반환 된 모든 요소에 대한 불필요한 루프
- 더 긴 코드.
그리고 그 차이는 외형 일 뿐이라고 발표하는 방법을 사용하는 것을 의미합니다.
당신은 단지 경고와 함께 살거나해야합니다.
나를 위해 일하는 유일한 방법은 반복적으로 사용하는 것입니다.
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);
}
내가 많은 방법으로 캐스트 문제가.
귀하의 질문에 답하기위한 "올바른 방법"은 없습니다. 이제 당신을 괴롭히는 경고 일 뿐이라면 경쟁을 피하는 가장 좋은 방법은 방법을 Query.list()
DAO로 래핑하는 것입니다.
public class MyDAO {
@SuppressWarnings("unchecked")
public static <T> List<T> list(Query q){
return q.list();
}
}
이렇게하면 @SuppressWarnings("unchecked")
한 번만 사용할 수 있습니다 .
List<Person> list = new ArrayList<Person>();
Criteria criteria = this.getSessionFactory().getCurrentSession().createCriteria(Person.class);
for (final Object o : criteria.list()) {
list.add((Person) o);
}
다음과 같은 ResultTransformer를 사용합니다.
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();
}
적절한 방법은 Hibernate Transformer를 사용하는 것입니다.
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);
Object []를 다수의 반복은 다수의 다수의 성능이 있습니다. 트랜스포머 사용에 대한 자세한 정보는 여기에서 사용할 수 있습니다. HQL 및 SQL 용 변환기
더 간단한 솔루션을 사용하면 즉시 사용할 수있는 맵 변환기를 사용할 수 있습니다.
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");
단지 Transformers를 사용하는 것 입니다. 유형 캐스트 예외가 발생했습니다.
sqlQuery.setResultTransformer(Transformers.aliasToBean(MYEngityName.class))
목록 요소의 고정 MYEngityName 유형이 아닌 반환 목록 요소에서 객체 배열을 얻었 기 때문에 작동하지 않았습니다.
sqlQuery.addScalar(-)
선택한 각 열과 해당 유형을 추가하고 특정 문자열 유형 열에 대해 해당 유형을 매핑 할 필요가 없을 때 다음과 같이 변경하면 저에게 효과적이었습니다. 처럼addScalar("langCode");
그리고 MYEngityName을 NextEnity와 조인 select *
했습니다. Query에서 반환 목록에 Object 배열을 제공 할 수 없습니다.
아래 코드 샘플 :
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();
도움이 될 수 있습니다. 이런 식으로 나를 위해 일합니다.
여기서 가장 좋은 해결책을 찾았습니다. 이 문제의 핵심은 addEntity 메서드입니다.
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);
}
}
'ProgramingTip' 카테고리의 다른 글
예쁜 인쇄 std :: tuple (0) | 2020.10.12 |
---|---|
CSS 선택기 (ID에 텍스트 일부 포함) (0) | 2020.10.12 |
특정 파일 형식을 제외하고 특정 폴더 아래의 모든 파일을 재귀 무시합니다. (0) | 2020.10.12 |
Emacs : 킬 링없이 텍스트를 삭제하는 방법? (0) | 2020.10.12 |
Rails 3.1에서 새 자산 경로 추가 (0) | 2020.10.12 |