is it possible to model a reference to "any" (entity) with JPA? Similar to a reference of type Object in Java, which can hold any object.
Thanks for your answer,
Dominik
You should think about representation of the reference in database.
If reference is represented by a single foreign key, then referenced column should be guaranteed to be unique for all possible referenced entities. In JPA it's possible only for entites in inheritance hierarchy, so you'll get a reference to the root of some inheretence hierarchy of entites instead of Object.
Reference may be represented by a pair of values <type of referenced entity, foreign key>. This case is not supported by plain JPA, but supported in Hibernate by Hibernate's own #Any annotation.
According to DataNucleus this is not possible (search in this for java.lang.Object):
http://www.datanucleus.org/products/accessplatform_1_1/jpa/types.html
For JDO we introduced our our Object-like abstract class called Subject which is annotated for persistence and extended all other persistable object from it. That works in JDO and I think it should work in JPA as well.
Related
I have an #Embeddable class with two fields: type and value. Both fields map to the corresponding database columns. The first one is enum and the latter one is an interface that has multiple implementations.
Only certain combinations of type and value are considered valid even if type and value are correct in isolation. How can I perform such validation, when I retrieve the entity that owns the #Embeddable from the database?
I could perform validation inside no-args-constructor of embeddable, but as far as I'm concerned, Hibernate creates new #Embeddable instance with no-args-constructor and then injects the values with Java Reflection API. Therefore, if I access these two fields inside the constructor they will be null.
Is there an approach to register some PostLoad hook for the #Embeddable classes that Hibernate will trigger? I though about declaring PostLoad inside the entity itself and then calling MyEmbeddable.validate directly. But I think it's a dirty approach.
I added the class-level annotation to validate the whole object. It did work. Check out this question for more details.
I know we persist collections (List, Set, Map, Collection) in two ways - annotate collection field with some JPA (javax.persistence) relation mapping annotation (#OneToMany, #ManyToMany) or use #ElementCollection JPA annotation.
1). Does JPA (or Hibernate underlying JPA) without above #OneToMany/#ElementCollection annotations persist List, Set, Map, Collection fields (fields not annotated with anything, their class is #Entity and #Id + #GeneratedValue present - and no more annotations).
Any primitive, enum and Serializable fields shall be persisted (as per JPA) - so collection fields shall also be persisted and then retrieved with entityManager.find - right? OK, order not preserved so I need to use #OrderColumn or #OrderBy JPA annotation (or Hibernate-specific deprecated #Sort or recommended now #SortNatural or #SortComparator ) additionally.
So my guess is that List<String> and List<MyPersonEntity> would be persisted and retrieved (as a field) without any annotations, but I'm not sure about List<MyNonEntityClass> (I think same goes for it).
What is the differnrece in persisting (allowed annotations, what can be persisted, what can be persisted as field without any annotations) List<String> vs List<MyPersonEntity> vs List<SomeNonEntity> exactly? Is there any such difference?
I googled a lot, read a few manuals, but found no direct answers.
Thorben Janssen writes
An #ElementCollection enables you to map a Collection of values **that are not an entity itself. **
It implies to me that List<MyPersonEntity> is persisted to DB without any annotations on List field, but List<OrderNotEntity> needs either #ElementCollection or #OneToMany/#ManyToMany annotation to be persisted. Does it throw an error or just silently fails to persist and then resolves to null when retrieved from database with entityManager.find?
[This][1] implies that #ElementCollection is needed only for List<BasicType> (List<String>, List<Integer>, etc) and List<Embeddable>, but not List<EntityClass>.
3). Can I use #ElementCollection with List<SerializableNonEntityClass> (any Serializable class is Basic, right?), List<MyEnumColor> (all enums are serializable), List<java.util.Date>, List<java.sql.Time> (also basic type), List<Set ?
JPA [Specification][2] does not define term "basic type", but provides a list of what can be annotated with #Basic:
11.1.6 Basic Annotation The Basic annotation is the simplest type of mapping to a database column. The Basic annotation can be applied to a
persistent property or instance variable of any of the following
types: Java primitive types, wrappers of the primitive types,
java.lang.String, java.math.BigInteger, java.math.BigDecimal,
java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time,
java.sql.Timestamp, byte[], Byte[], char[], Character[], enums, and
any other type that implements Serializable. As described in Section
2.8, the use of the Basic annotation is optional for persistent fields and properties of these types. If the Basic annotation is not
specified for such a field or property, the default values of the
Basic annotation will apply
2.8 Mapping Defaults for Non-Relationship Fields or Properties If a persistent field or property other than a relationship property is not
annotated with one of the mapping annotations defined in Chapter 11
(or equivalent mapping information is not specified in the XML
descriptor), the following default mapping rules are applied in order:
• If the type is a class that is annotated with the Embeddable
annotation, it is mapped in the same way as if the field or property
were annotated with the Embedded annotation. See Sections 11.1.15 and
11.1.16. • If the type of the field or property is one of the following, it is mapped in the same way as it would if it were
annotated as Basic: Java primitive types, wrappers of the primitive
types, java.lang.String, java.math.BigInteger, java.math.BigDecimal,
java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time,
java.sql.Timestamp, byte[], Byte[], char[], Character[], enums, any
other type that implements Serializable.
I don't understand that reference to section 2.8. So if I don't use #ElementCollection - no problem, mapping to DB also succeeds and everything is persisted just fine???
[1]: https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection#:~:text=It%20is%20meant%20to%20handle,a%20collection%20of%20String%20s)
[2]: https://download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf?AuthParam=1648386141_7549cef1d21f5581b4966d8d8ef70de4
I have three classes that are subclasses of the abstract superclass Automobile. I'm using the single table inheritance model and a #MappedSuperclass for the automobile class. The subclasses are Car, Truck, and Van.
I want to query the automobile class, but have the different subclasses returned. I've written a couple queries and done some research, but it seems like it is not possible to query against MappedSuperclasses. I have also tried to do NativeSqlQueries, but I can't seem to be able to figure out how to specifiy multiple ResultSetMappings.
Is there anyway to accomplish this?
You cannot use a mapped-superclass in the query. If you want to use Automobile in the query, don't mark it as mapped-superclass, instead mark it as an entity.
Following is from the JPA 2.0 Spec, second paragraph is what's relevant in your case -
2.11.2 Mapped Superclasses
An entity may inherit from a superclass that provides persistent entity state and mapping information, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.
A mapped superclass, unlike an entity, is not queryable and must not be passed as an argument to EntityManager or Query operations. Persistent relationships defined by a mapped superclass must
be unidirectional.
I will implement an entity class, something like:
#Entity
public class XXXEntity {
#Id
private Long id;
private Object entity;
}
But I am not sure how to map the Object type field?
Actually, in my project the object types contain several other entities, like A, B, C. (all A,B, and C implement Serilizable interface)
I want to annotate it as #Lob, but I am not sure it is correct? Because Object doesn't implement Serilizable interface.
Any ideas about that? Thanks.
You can not annotate Object field as #Lob. According to spec: "A Lob may be either a binary or character type."
You should decide whether A, B and C are entities or state field values. If they are entities and they can be referenced, queried by their properties, create a common super class a go with the inheritance.
If they are just an object then using Lob and implementing Serializable should suffice. If the JPA provider requires you to replace Object with something else, as you have stated you can use Serializable interface, if that does not work then a common super class which implements Serializable.
It seems to me you want to use it as "ValueObject" (as u mentioned serializable) instead of "Entity".
It is fine if you treat the field as ValueObject. Using Lob should be fine (and you can always find workaround by manually serializing it).
But if you want to treat them as "Entity ", it will never be reasonable to declare it as ref to "Object". One of the most obvious argument is Object is NOT an Entity, as it doesn't contains any entity identity.
No, it is not correct to annotate it with #Lob. You cannot directly annotate arbitrary Object as a persistent attribute. JPA provider have no way to know how to persist it.
According JPA 2.0 specification persistent attribute must be one of following:
Java primitive types; java.lang.String; other Java serializable types
(including wrappers of the primitive types,
java.math.BigInteger,java.math.BigDecimal,java.util.Date,java.util.Calendar[5],
java.sql.Date, java.sql.Time, java.sql.Timestamp, byte[], Byte[],
char[], Character[], and user-defined types that implement the
Serializable interface); enums; entity types; collections of entity
types; embeddable classes; collections of basic and embeddable types.
You should redesign model such a way that there is no need to persist basically typeless data.
Does JPA support embedding a class attribute whose type is a parameterized generic or java.lang.Object? For example:
public class Foo<T>;
{
private T param1;
private Object param2;
}
I have a use case where I have a class that "wraps" some arbitrary class (the generic T or java.lang.Object) via aggregation plus contains primitive types representing metadata about the wrapped object.
In this case, I'd like there to be DB tables for each of things being wrapped that also contain columns for the metadata. These metadata columns would be duplicated across all tables representing the wrapped embedded objects.
I'd like there to be DB tables for each of things being wrapped that also contain columns for the metadata. These metadata columns would be duplicated across all tables representing the wrapped embedded objects.
You could maybe persist Object or T as a #Lob but I don't think that the above is possible, I don't see how you could express the mappings, how a JPA provider could be aware of the tables.
See also
Enterprise JavaBeans - JPA Generic entities classes Mappedsuperclass are not possible!