对于使用联接表的更复杂的查询,需要具有别名字段名称的本机 SQL + 重新映射以接收托管实体。
但是,SQL 别名的映射会导致无法找到别名字段的异常。任何人都可以在下面的代码中检测到错误,或者 SQLResultSetMapping 是否损坏?(下面的示例故意简单以便快速检查)
关系型数据库 H2、DDL
create table A(
ID INTEGER DEFAULT NOT NULL AUTO_INCREMENT PRIMARY KEY,
VAL VARCHAR(10)
);
insert into A (val) values ('val1');
insert into A (val) values ('val2');
Java 类
@Entity
@NamedNativeQuery(name = "queryall",
query="select ID as AID, val from A",
resultSetMapping = "mapping")
@SqlResultSetMapping(name = "mapping",
entities = @EntityResult(
entityClass = A.class,
fields = {@FieldResult(name = "ID", column = "AID")})
)
public class A implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Integer id;
@Column(name = "VAL")
private String val;
public A() {
}
public A(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
@Override
public String toString() {
return "entities.A[ id=" + id +", val="+val+ " ]";
}
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("JavaApplication6PU");
EntityManager em = entityManagerFactory.createEntityManager();
Query sqlQuery = em.createNamedQuery("queryall");
List list = sqlQuery.getResultList();
for (Iterator<A> iterator = list.iterator(); iterator.hasNext();) {
a = iterator.next();
System.out.println(String.format("entity %s, managed: %s", a, em.contains(a)));
}
}
}
执行停止异常:
[EL Warning]: 2018-01-12 21:45:42.748--UnitOfWork(1823014131)--Exception
[EclipseLink-6044] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd):
org.eclipse.persistence.exceptions.QueryException
Exception Description: The primary key read from the row [DatabaseRecord(
A.ID => null
A.VAL => val1)] during the execution of the query was detected to be null.
Primary keys must not contain null.
Query: ResultSetMappingQuery(name="queryall" referenceClass=A sql="select ID as AID, val from A")
换句话说,这意味着:没有发生映射 -> 未找到别名字段
在临时查询中宣布映射时也是如此。
Query sqlQuery = em.createNativeQuery("select ID as AID, val from A","mapping");
如果使用 resultClass 而不是 resultSetMapping 并且不存在 SQL 别名,则输出应为正常。(这证明没有字段拼写错误或任何其他错误)
@NamedNativeQuery(name = "queryall",
query="select ID, val from A",
resultClass = A.class)
输出:
entity entities.A[ id=1, val=val1 ], managed: true
entity entities.A[ id=2, val=val2 ], managed: true