What is @StaticMetamodel and SingularAttribute<Obj,Obj>?
As per documentation:
A static metamodel is a series of classes that "mirror" the entities and embeddables in the domain model and provide static access to the metadata about the mirrored class's attributes.
The static metamodel has the following properties:
- For each managed class
X
in packagep
, a metamodel classX_
in packagep
is created. - For every persistent non-collection-valued attribute
y
declared by classX
, where the type ofy
isY
, the metamodel class must contain a declaration as follows:
SingularAttribute
example:
public static volatile SingularAttribute<X, Y> y;
The static metamodel is useful for creating type-safe queries with the JPA's Criteria API.
For example, let's have the following two entities, Order
and Item
:
@Entity
public class Order {
@Id
@GeneratedValue
Integer id;
@ManyToOne
Customer customer;
@OneToMany
Set<Item> items;
BigDecimal totalCost;
// accessors
}
and the Item
entity:
@Entity
public class Item {
@Id
@GeneratedValue
Integer id;
int quantity;
@ManyToOne
Order order;
// accessors
}
Here's a typesafe criteria query, build with the Criteria API:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
SetJoin<Order, Item> itemNode = cq.from(Order.class).join(Order_.items);
cq.where(cb.equal(itemNode.get(Item_.id), 5)).distinct(true);
Note the usage of Item_.id
and Order_.item
. Those access statically the static meta-model properties (which mirror the entity properties) and this way it's ensured that the query is build properly.
I've been thinking about this a lot lately as I've been trying to learn and understand JPA. I believe I have an answer to your question: Why do we need MetaModels, and why can't we just use the Entity Model?
Take a look at this entity:
@Entity
public class Item {
@Id
@GeneratedValue
Integer id;
int quantity;
@ManyToOne
Order order;
// accessors
}
Note that none of the properties on the Entity have the keyword static. That means that in order to use them, we need to create a new Object.
When we are building queries with CriteriaBuilder, we don't need to create an object... we just want to use the properties on the Entity to generate our query. This is the reason we have MetaModels! They create static properties that we can access without having to create an object. So we can can do things like Konstantin mentioned:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
SetJoin<Order, Item> itemNode = cq.from(Order.class).join(Order_.items);
cq.where(cb.equal(itemNode.get(Item_.id), 5)).distinct(true);
Here, we aren't making an "Item" object... we just need to know the properties of it. The static properties on the MetaModel enable us to do so!