Da dies eine sehr häufige Frage ist, habe ich diesen Artikel geschrieben , auf dem diese Antwort basiert.
Nehmen wir an , unsere Anwendung verwendet die folgende Post
, PostComment
, PostDetails
, und Tag
Einrichtungen, die eine Eins-zu-viele bilden, eins-zu-eins, und many-to-many - Tabelle Beziehungen :
So generieren Sie das Metamodell für JPA-Kriterien
Mit dem hibernate-jpamodelgen
von Hibernate ORM bereitgestellten Tool können die Projekteinheiten gescannt und das Metamodell für JPA-Kriterien generiert werden. Sie müssen lediglich Folgendes annotationProcessorPath
zur maven-compiler-plugin
Maven- pom.xml
Konfigurationsdatei hinzufügen :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${hibernate.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</plugin>
Wenn das Projekt kompiliert wird, können Sie sehen, dass im target
Ordner die folgenden Java-Klassen generiert werden:
> tree target/generated-sources/
target/generated-sources/
└── annotations
└── com
└── vladmihalcea
└── book
└── hpjp
└── hibernate
├── forum
│ ├── PostComment_.java
│ ├── PostDetails_.java
│ ├── Post_.java
│ └── Tag_.java
Tag-Entität Metamodell
Wenn die Tag
Entität wie folgt zugeordnet ist:
@Entity
@Table(name = "tag")
public class Tag {
@Id
private Long id;
private String name;
//Getters and setters omitted for brevity
}
Die Tag_
Metamodel-Klasse wird folgendermaßen generiert:
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Tag.class)
public abstract class Tag_ {
public static volatile SingularAttribute<Tag, String> name;
public static volatile SingularAttribute<Tag, Long> id;
public static final String NAME = "name";
public static final String ID = "id";
}
Das SingularAttribute
wird für die Basis- id
und name
Tag
JPA-Entitätsattribute verwendet.
Post-Entität Metamodell
Die Post
Entität wird wie folgt zugeordnet:
@Entity
@Table(name = "post")
public class Post {
@Id
private Long id;
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
@OneToOne(
mappedBy = "post",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY
)
@LazyToOne(LazyToOneOption.NO_PROXY)
private PostDetails details;
@ManyToMany
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Tag> tags = new ArrayList<>();
//Getters and setters omitted for brevity
}
Die Post
Einheit hat zwei grundlegende Eigenschaften, id
und title
, eine Eins-zu-viele - comments
Sammlung, eine Eins-zu-Eins - details
Verbindung und eine Viele-zu-viele - tags
Sammlung.
Die Post_
Metamodel-Klasse wird wie folgt generiert:
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Post.class)
public abstract class Post_ {
public static volatile ListAttribute<Post, PostComment> comments;
public static volatile SingularAttribute<Post, PostDetails> details;
public static volatile SingularAttribute<Post, Long> id;
public static volatile SingularAttribute<Post, String> title;
public static volatile ListAttribute<Post, Tag> tags;
public static final String COMMENTS = "comments";
public static final String DETAILS = "details";
public static final String ID = "id";
public static final String TITLE = "title";
public static final String TAGS = "tags";
}
Die Grundlagen id
und title
Attribute sowie die Eins-zu-Eins- details
Zuordnung werden durch eine SingularAttribute
Weile dargestellt, während die Sammlungen comments
und tags
durch die JPA dargestellt werden ListAttribute
.
PostDetails-Entität Metamodell
Die PostDetails
Entität wird wie folgt zugeordnet:
@Entity
@Table(name = "post_details")
public class PostDetails {
@Id
@GeneratedValue
private Long id;
@Column(name = "created_on")
private Date createdOn;
@Column(name = "created_by")
private String createdBy;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
@JoinColumn(name = "id")
private Post post;
//Getters and setters omitted for brevity
}
Alle Entitätsattribute werden von der JPA SingularAttribute
in der zugehörigen PostDetails_
Metamodel-Klasse dargestellt:
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(PostDetails.class)
public abstract class PostDetails_ {
public static volatile SingularAttribute<PostDetails, Post> post;
public static volatile SingularAttribute<PostDetails, String> createdBy;
public static volatile SingularAttribute<PostDetails, Long> id;
public static volatile SingularAttribute<PostDetails, Date> createdOn;
public static final String POST = "post";
public static final String CREATED_BY = "createdBy";
public static final String ID = "id";
public static final String CREATED_ON = "createdOn";
}
PostComment-Entität Metamodell
Das PostComment
ist wie folgt abgebildet:
@Entity
@Table(name = "post_comment")
public class PostComment {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
//Getters and setters omitted for brevity
}
Alle Entitätsattribute werden von der JPA SingularAttribute
in der zugehörigen PostComments_
Metamodel-Klasse dargestellt:
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(PostComment.class)
public abstract class PostComment_ {
public static volatile SingularAttribute<PostComment, Post> post;
public static volatile SingularAttribute<PostComment, String> review;
public static volatile SingularAttribute<PostComment, Long> id;
public static final String POST = "post";
public static final String REVIEW = "review";
public static final String ID = "id";
}
Verwenden des JPA-Kriterien-Metamodells
Ohne das JPA-Metamodell würde eine Kriterien-API-Abfrage, die die nach dem PostComment
zugehörigen Post
Titel gefilterten Entitäten abrufen muss, folgendermaßen aussehen:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<PostComment> query = builder.createQuery(PostComment.class);
Root<PostComment> postComment = query.from(PostComment.class);
Join<PostComment, Post> post = postComment.join("post");
query.where(
builder.equal(
post.get("title"),
"High-Performance Java Persistence"
)
);
List<PostComment> comments = entityManager
.createQuery(query)
.getResultList();
Beachten Sie, dass wir post
beim Erstellen der Join
Instanz das title
String-Literal und beim Verweisen auf das String-Literal verwendet haben Post
title
.
Mit dem JPA-Metamodell können wir hartcodierte Entitätsattribute vermeiden, wie im folgenden Beispiel dargestellt:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<PostComment> query = builder.createQuery(PostComment.class);
Root<PostComment> postComment = query.from(PostComment.class);
Join<PostComment, Post> post = postComment.join(PostComment_.post);
query.where(
builder.equal(
post.get(Post_.title),
"High-Performance Java Persistence"
)
);
List<PostComment> comments = entityManager
.createQuery(query)
.getResultList();
Das Schreiben von API-Abfragen für JPA-Kriterien ist viel einfacher, wenn Sie ein Code-Vervollständigungstool wie Codota verwenden. In diesem Artikel finden Sie weitere Informationen zum Codota IDE-Plugin.
Angenommen, wir möchten eine DTO-Projektion abrufen, während wir die Post
title
und die PostDetails
createdOn
Attribute filtern .
Wir können das Metamodell beim Erstellen der Join-Attribute sowie beim Erstellen der DTO-Projektionsspalten-Aliase oder beim Verweisen auf die Entitätsattribute verwenden, die gefiltert werden müssen:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> query = builder.createQuery(Object[].class);
Root<PostComment> postComment = query.from(PostComment.class);
Join<PostComment, Post> post = postComment.join(PostComment_.post);
query.multiselect(
postComment.get(PostComment_.id).alias(PostComment_.ID),
postComment.get(PostComment_.review).alias(PostComment_.REVIEW),
post.get(Post_.title).alias(Post_.TITLE)
);
query.where(
builder.and(
builder.like(
post.get(Post_.title),
"%Java Persistence%"
),
builder.equal(
post.get(Post_.details).get(PostDetails_.CREATED_BY),
"Vlad Mihalcea"
)
)
);
List<PostCommentSummary> comments = entityManager
.createQuery(query)
.unwrap(Query.class)
.setResultTransformer(Transformers.aliasToBean(PostCommentSummary.class))
.getResultList();
Cool, oder?