获取对象的部分属性组成一个对象
需求:一篇文章有很多属性及关联对象.在SEO的设置中可能只关心title,keywords,description.
解决:新建一个ArticleMeta 类,从Article中取出title,keywords,description填到ArticleMeta
代码
@Override
public ArticleMeta getArticleMeta(long articleId) {
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq=cb.createTupleQuery();
Root<Article> root = cq.from(Article.class);
Expression<Long> id=root.get("id");
Expression<String> source=root.get("source");
Expression<Boolean> status=root.get("status");
Expression<String> keywords=root.get("keywords");
Expression<String> descript=root.get("descript");
cq.multiselect(id.alias("ID"),source.alias("SOURCE"),status.alias("STATUS"),keywords.alias("KEYWORDS"),descript.alias("DESCRIPT"));
cq.where(cb.equal(id, articleId));
TypedQuery<Tuple> tq=entityManager.createQuery(cq);
Tuple t=tq.getSingleResult();
ArticleMeta am=new ArticleMeta();
am.setId(t.get("ID",Long.class));
am.setKeywords(t.get("KEYWORDS",String.class));
am.setDescript(t.get("DESCRIPT",String.class));
am.setSource(t.get("SOURCE",String.class));
am.setStatus(t.get("STATUS",Boolean.class));
return am;
}
JPA 2.1增加了ConstructorResult ,来实现这个功能更轻松.ArticleMeta需要加几个注解.
/**
* 值对象,不与具体的表关联
* @author xiaofanku
*/
@Entity
public class ArticleMeta implements Serializable {
@Id
private long id;
/**
* 状态
*/
private boolean status=true;
/**
* 关键词
*/
private String keywords;
/**
* 简述
*/
private String descript;
/**
* 来源
*/
private String source="站内原创";
/**
* 作者的ID
*/
private int authorId;
public ArticleMeta(){
super();
}
public ArticleMeta(
long id,
boolean status,
String keywords,
String descript,
String source,
int authorId) {
this.id = id;
this.status=status;
this.keywords = keywords;
this.descript = descript;
this.source= source;
this.authorId = authorId;
}
//GET/SET
}
在Article中加@NamedNativeQuery和@SqlResultSetMapping两个注解,需要注意这里用的是物理表名和字段名,不能用实体类名表示物理表名.不能用属性名表示物理表的字段名
@NamedNativeQuery(
name="findArticleMeta",
query="SELECT a.id, a.status, a.keywords, a.descript, a.source, a.user AS authorId FROM apo_article a WHERE a.id = ?",
resultSetMapping="article-meta"
)
@SqlResultSetMapping(name="article-meta",
classes={
@ConstructorResult(targetClass=ArticleMeta.class, columns={
@ColumnResult(name="id", type=Long.class),
@ColumnResult(name="status", type=Boolean.class),
@ColumnResult(name="keywords", type=String.class),
@ColumnResult(name="descript", type=String.class),
@ColumnResult(name="source", type=String.class),
@ColumnResult(name="authorId", type=Integer.class)
})
}
)
public class Article implements Serializable {
}
DAO层的方法如下:
@Override
public ArticleMeta getArticleMeta(long articleId) {
TypedQuery<ArticleMeta> query=entityManager.createNamedQuery("findArticleMeta",ArticleMeta.class).setParameter(1, articleId);
return query.getSingleResult();
}
OneToOne 和 ManyToOne关联对象的lazy加载
需求:当判断一个对象的存在如否,可能不希望去加载关联对象;或记录列表只需要固有的属性,用不到关联对象
解决:fetch=FetchType.LAZY, 为什么有时不启作用呢?
Lazy is not working
Lazy OneToOne and ManyToOne relationships typically require some form of weaving or byte-code generation. Normally when running in JSE an agent option is required to allow the byte-code weaving, so ensure you have the agent configured correctly. Some JPA providers perform dynamic subclass generation, so do not require an agent.
Java Persistence/Relationships
相关设置:
persistence.xml
<property name="eclipselink.weaving.lazy" value="true"/>
junit测试,pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit4</artifactId>
<version>2.19.1</version>
</dependency>
</dependencies>
<configuration>
<argLine>-Dfile.encoding=${project.build.sourceEncoding}</argLine>
<argLine>-javaagent:d:\\eclipselink.jar</argLine>
</configuration>
</plugin>
如果不用maven
1> Netbeans8.x中的javaagent在:项目名右击>属性>弹出窗口中类别:运行
2> 方法代码:
private Page<Article> getAll(Pageable pageable) {
Query query=entityManager.createQuery("SELECT a FROM Article a WHERE a.status=TRUE");
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
//ETC
}
3> 测试:没有lazy或lazy不启作用时的sql输出,可见关联的对象都查了
--SELECT ID AS a1, DESCRIPT AS a2, KEYWORDS AS a3, PUBLISH AS a4, SOURCE AS a5, STATUS AS a6, TITLE AS a7, channel AS a8, type AS a9, user AS a10, album AS a11, hash AS a12 FROM apo_article WHERE (STATUS = ?) LIMIT ?, ?
bind => [true, 0, 10]
--SELECT CID, DATE, ENAME, NAME, STATUS, master FROM apo_category WHERE (CID = ?)
bind => [2]
--SELECT UID, ACTIVEDATE, MAIL, NICKNAME, REGISTDATE, SALT, SHA256PSWD, STATUS FROM apo_author WHERE (UID = ?)
bind => [1]
--SELECT AID, DATE, STATUS, master, cover FROM apo_album WHERE (AID = ?)
bind => [52]
--SELECT RID, HASH, HTTPCODE, LOCAL, MIMETYPE, URL FROM apo_imageLink WHERE (RID = ?)
bind => [53]
--SELECT HASH, CONTENT FROM apo_article_content WHERE (HASH = ?)
bind => [dc87d9262903b6f8fc020134b6803c51]
--SELECT ID, DESCRIPT, KEYWORDS, PUBLISH, SOURCE, STATUS, TITLE, channel, type, user, album, hash FROM apo_article WHERE (hash = ?)
bind => [dc87d9262903b6f8fc020134b6803c51]
--SELECT AID, DATE, STATUS, master, cover FROM apo_album WHERE (AID = ?)
bind => [55]
--SELECT RID, HASH, HTTPCODE, LOCAL, MIMETYPE, URL FROM apo_imageLink WHERE (RID = ?)
bind => [56]
--SELECT HASH, CONTENT FROM apo_article_content WHERE (HASH = ?)
bind => [72b8ab125ac8407042d5a9faa768d3fe]
--SELECT ID, DESCRIPT, KEYWORDS, PUBLISH, SOURCE, STATUS, TITLE, channel, type, user, album, hash FROM apo_article WHERE (hash = ?)
bind => [72b8ab125ac8407042d5a9faa768d3fe]
4> 测试:lazy作用时的sql输出,没有关联对象的select
--SELECT ID AS a1, DESCRIPT AS a2, KEYWORDS AS a3, PUBLISH AS a4, SOURCE AS a5, STATUS AS a6, TITLE AS a7, channel AS a8, type AS a9, user AS a10, album AS a11, hash AS a12 FROM apo_article WHERE (STATUS = ?) LIMIT ?, ?
bind => [true, 0, 10]
对象持久的多步骤,部分属性无刷新
需求:一篇文章的持久化,分为多步骤.例如:第一步:文章的标题和内容,第二步:SEO信息,第三步:关联相关文章
解决: 每次update时后加上flush和clear
affect=query.executeUpdate();
entityManager.flush();
entityManager.clear();
关于Duplicates
需求:如果表需要唯一性约束,但关联关系是集合,就不是作级联操作,尤其是persist.
A List in Java supports duplicate entries, and a Set does not. In the database, duplicates are generally not supported. Technically it could be possible if a JoinTable is used, but JPA does not require duplicates to be supported, and most providers do not.
If you require duplicate support, you may need to create an object that represents and maps to the join table. This object would still require a unique Id, such as a GeneratedValue.
Mapping a Join Table with Additional Columns