Bu çok yaygın bir soru olduğu için bu cevabın dayandığı bu makaleyi yazdım .
Uygulamamızın aşağıdakileri kullandığını varsayalım Post
, PostComment
, PostDetails
ve Tag
bir tane çoğa oluşturan kişiler, bire-bir ve birçok çoğa tablo ilişkileri :
JPA Ölçütleri Metamodeli nasıl oluşturulur?
hibernate-jpamodelgen
Hazırda ORM tarafından sağlanan alet proje varlıkları tarama ve JPA Kriterlerini Metamodel üretmek için kullanılabilir. Tek yapmanız gereken tek şey aşağıdaki ekleyin annotationProcessorPath
için maven-compiler-plugin
Maven içinde pom.xml
yapılandırma dosyasının:
<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>
Şimdi, proje derlendiğinde, target
klasörde aşağıdaki Java sınıflarının oluşturulduğunu görebilirsiniz:
> tree target/generated-sources/
target/generated-sources/
└── annotations
└── com
└── vladmihalcea
└── book
└── hpjp
└── hibernate
├── forum
│ ├── PostComment_.java
│ ├── PostDetails_.java
│ ├── Post_.java
│ └── Tag_.java
Etiket varlığı Metamodel
Eğer Tag
aşağıdaki gibi varlık eşleştirilmiş:
@Entity
@Table(name = "tag")
public class Tag {
@Id
private Long id;
private String name;
}
Tag_
Metamodel sınıfı böyle oluşturulur:
@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";
}
SingularAttribute
Temel için kullanılır id
ve name
Tag
JPA varlık öznitelikleri.
Gönderi varlığı Metamodel
Post
Varlık böyle eşleştirilmiş:
@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<>();
}
Post
Varlık iki temel özelliklere sahiptir, id
ve title
, bire-birçok comments
koleksiyon, bire-bir details
ilişki ve bir çok-çok sayıda tags
koleksiyon.
Post_
Aşağıdaki gibi Metamodel sınıfı oluşturulur:
@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";
}
Temel id
ve title
özniteliklerin yanı sıra bire bir details
ilişki, bir SingularAttribute
süre ile temsil edilir comments
ve tags
koleksiyonları JPA tarafından temsil edilir ListAttribute
.
PostDetails varlık Metamodel
PostDetails
Varlık böyle eşleştirilmiş:
@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;
}
Tüm varlık öznitelikleri SingularAttribute
, ilişkili PostDetails_
Metamodel sınıfında JPA tarafından temsil edilecektir :
@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 varlığı Metamodel
Aşağıdaki PostComment
gibi eşlenir:
@Entity
@Table(name = "post_comment")
public class PostComment {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
}
Ve tüm varlık öznitelikleri SingularAttribute
, ilişkili PostComments_
Metamodel sınıfında JPA tarafından temsil edilir :
@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";
}
JPA Ölçütleri Metamodelini Kullanma
JPA Metamodel olmadan, PostComment
ilişkili Post
başlıklarına göre filtrelenen varlıkları getirmesi gereken bir Criteria API sorgusu şu şekilde görünür:
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();
Kullandığımız bu Bildirimi post
oluştururken dize Join
örneği ve kullandığımız title
başvururken dize Post
title
.
JPA Metamodel, aşağıdaki örnekte gösterildiği gibi, varlık özniteliklerini sabit kodlamamıza izin verir:
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();
Codota gibi bir kod tamamlama aracı kullanıyorsanız, JPA Criteria API sorguları yazmak çok daha kolaydır. Check out bu makaleyi Codota IDE eklentisi hakkında daha fazla ayrıntı için.
Ya da, hadi biz bir getirme istediğini söylüyorsun DTO projeksiyonunu filtreleme süre Post
title
ve PostDetails
createdOn
özelliklerini.
Metamodeli birleştirme özniteliklerini oluştururken ve ayrıca DTO projeksiyon sütunu takma adlarını oluştururken veya filtrelememiz gereken varlık özniteliklerine referans verirken kullanabiliriz:
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();
Harika, değil mi?