I read this in the EJB/JPA Book:
"Even if you mark the property as LAZY for a #Basic type, the persistence provider is still allowed to load the property eagerly. This is due to the fact that this feature requires class-level instrumentation. It should also be noted that lazy loading is neither really useful nor a significant performance optimization. It is best practice to eagerly load basic properties."
QUESTION 1)
If I set property as an LAZY, why e persistence provider is still allowed to load the property eagerly? when this happens? and why? is this for primitives only?
QUESTION 2)
"The #Basic annotation is the simplest form of mapping for a persistent property. This is the default mapping type for properties which are primitives, primitive wrapper types"
If I use does not use primitive or wrapper (for instance I use my class object), will he persistence provider is still allowed to load the property eagerly?
QUESTION 3)
"You do not need to tell your persistence manager explicitly that you're mapping a basic property because it can usually figure out how to map it to JDBC using the property's type."
As I understand this happens when I use primitives or wrappers, don't I? And how does it figure out how to map? Is there any obvious rule?
QUESTION 1)If I set property as an LAZY, why e persistence provider is
still allowed to load the property eagerly? when this happens? and
why? is this for primitives only?
Because of performance issues: the JPA provider has the right (according to the JPA spec) to decide that it is better to fetch the field eagerly. This is valid also for wrapper fields & Strings. It is not specified when this happens, which means that can happen when the JPA provider considers it needed.
QUESTION 2)"The #Basic annotation is the simplest form of mapping for
a persistent property. This is the default mapping type for properties
which are primitives, primitive wrapper types"
If I use does not use primitive or wrapper (for instance I use my
class object), will he persistence provider is still allowed to load
the property eagerly?
Actually yes, also for relationships you have the same rule, although almost always the JPA provider will consider your hint. Of course: when you have a field of type YouClass, you are not allowed to annotate it with #Basic and must use #ManyToOne-like annotations. You will read further about them.
QUESTION 3) "You do not need to tell your persistence manager
explicitly that you're mapping a basic property because it can usually
figure out how to map it to JDBC using the property's type."
As I understand this happens when I use primitives or wrappers, don't
I? And how does it figure out how to map? Is there any obvious rule?
That happens will all types listed in the documentation of the #Basic annotation, not only those that you enumerated. The rule is pretty simple: String types are mapped as VARCHAR/CHAR like columns, number-fields like NUMBER (or DECIMAL) and so further.
Related
Ok, so here [1] is the great read, how do really correctly define hashcode/equals, namely with respect to object hierarchies. But here I'd like to ask about #pitfall 3 from that article, which shows bizarre behavior when hashcode/equals are defined on mutable fields and Set is used for collections. We cannot use final fields and parameterized constructor only, due to JPA spec. So what are the means to avoid these gotchas? What do you use?
Well, obviously one is to avoid using Set in JPA entities. Does not seems very nice. Another solution could be to "unsupport" setters after equals method was called, but that's ridiculous and equals surely shouldn't have side-effect.
So how do you cope with that? Aside from not-knowing/ignoring it, which probably would be default action in java world...
[1] https://www.artima.com/lejava/articles/equality.html
If entity is detached you need to override equal and hashcode1. Every entity has to have #Id. ID is immutable. Entities should implement equal and hashcode based on primary key ID.
Pitfall 3 deals with mutable object. Cannot by applied on entity with immutable ID.
Guide to Implementing equals() and hashCode() with Hibernate
Consider you are doing some integration testing, you are storing some bigger entity into db, and then read it back and would like to compare it. Obviously it has some associations as well, but that's just a cherry on top of very unpleasant cake. How do you compare those entities? I saw lot of incorrect ideas and feel, that this has to be written manually. How you guys do that?
Issues:
you cannot use equals/hashcode: these are for natural Id.
you cannot use subclass with fixed equals, as that would test different class and can give wrong results when persisting data as data are handled differently in persistence context.
lot of fields: you don't want to type all comparisons by hand. You want reflection.
#Temporal annotations: you cannot use trivial "reflection equals" approaches, because #Temporal(TIMESTAMP) java.util.Date <> java.sql.Date
associations: typical entity you would like to have properly tested will have several associations, thus tool/approach ideally should support deep comparison. Also cycles in object graph can ruin the fun.
Best solution what I found:
don't use transmogrifying data types (like Date) in JPA entities.
all associations should be initialized in entity, because null <> empty list.
calculate externaly toString via say ReflectionToStringBuilder, and compare those. Reason for that is to allow entity to have its toString, tests should not depend that someone does not change something. Theoretically, toString can be deep, but commons recursive toStringStyle includes object identifier, which ruins it.
I though, that I could use json format to string, but commons support that only for shallow toString, Jackson (without further instructions on entity) fails on cycles over associations
Alternative solution would be actually declaring subclasses with generated id (say lombok) and use some automatic mapping tool (say remondis mapper), with option to overcome differences in Dates/collections.
But I'm listening. Does anyone posses better solution?
I am using MapStruct to provide bean mapping between different systems, and I have reached a point where the only way to map a specific property is to add it as a Map entry to the target object with the field name as key.
I can do this using a very long expression where I set the entire map using guava ImmutableMap builder, but is there a more elegant and safe way of providing this mapping? Setter method would expect two parameters in this case.
This is currently not support in MapStruct. There is already an open feature request #1075 for support like this.
I was reading over the docs regarding Eclipselink's support for #OrderColumn. It looks like this only applies to List and not Set. The reason I ask is because I have a ManyToMany bi-directional relationship (using a join table) which is a Set and is implemented with a HashSet because the collection can't have duplicates.
I wanted to order the entries in this set using #OrderColumn, but it appears I can only apply this to List, however using List will break my unique requirement. Is this understanding correct?
If so what is the recommended strategy for this case?
Thanks,
-Noah
This looks similar to the following question:
Why cannot a JPA mapping attribute be a LinkedHashset?
The Set interface does not define ordering of elements, so your set needs to be a concrete implementation like a TreeSet or LinkedHashSet implementation, not just any old Set. But your JPA provider is generally going to use its own collection implementations with special magic to handle lazy loading.
The above answer suggests that there may be some EclipseLink-specific workaround if you are willing to give up lazy loading.
I can think of two options, neither one perfect:
just use a List and rely on business logic to enforce uniqueness, with DB UNIQUE constraints as a backstop. Honestly, I end up using List for collections almost reflexively, even when Set would have been more appropriate; I admit it's sloppy but has yet to cause any significant problems for me in years of practice.
use a Set and change #ManyToMany to #OneToMany, and make your join table w/order column an actual entity that implements Comparable using the order column. Then, overload your getter method to do something like
if (! this.set instanceof TreeSet)
this.set = new TreeSet<T>(this.set);
return this.set;
i'm trying to figure wether there's a difference betweeen anotating (let's take #id as an example) a getter method and the concerned field directly , in case i annotate the field , does JPA use some kind of reflection to invok the corresponding getter ?
because in my case i'm trying to obfuscate my entity classes , so i'm looking for a way to keep the business logic since the getters will be renamed into something like aaa() .
Here's what the section 2.3.1 of the JPA2 specification says:
By default, a single access type (field or property access) applies to
an entity hierarchy. The default access type of an entity hierarchy is
determined by the placement of mapping annotations on the attributes
of the entity classes and mapped superclasses of the entity hierarchy
that do not explicitly specify an access type. An access type is
explicitly specified by means of the Access annotation[6], as
described in section 2.3.2. When annotations are used to define a
default access type, the placement of the mapping annotations on
either the persistent fields or persistent properties of the entity
class specifies the access type as being either field- or
property-based access respectively.
When field-based access is used, the object/relational mapping annotations for the entity class annotate the instance variables, and
the persistence provider runtime accesses instance variables directly.
All non-transient instance variables that are not annotated with the
Transient annotation are persistent.
When property-based access is used, the object/relational mapping annotations for the entity class annotate the getter property
accessors[7], and the persistence provider runtime accesses persistent
state via the property accessor methods. All properties not annotated
with the Transient annotation are persistent.
Mapping annotations must not be applied to fields or properties that are transient or Transient.
All such classes in the entity hierarchy whose access type is
defaulted in this way must be consistent in their placement of
annotations on either fields or properties, such that a single,
consistent default access type applies within the hierarchy. Any
embeddable classes used by such classes will have the same access type
as the default access type of the hierarchy unless the Access
annotation is specified as defined below. It is an error if a default
access type cannot be determined and an access type is not explicitly
specified by means of annotations or the XML descriptor. The behavior
of applications that mix the placement of annotations on fields and
properties within an entity hierarchy without explicitly specifying
the Access annotation is undefined.
So, if you want to avoid problems with the obfuscation, then annotate the fields and not the getters, consistently, or use the #Access annotation to force field access type.
JPA allows for two types of access to the data of a persistent class. Field access which means that it maps the instance variables (fields) to columns in the database and Property access which means that is uses the getters to determine the property names that will be mapped to the db. What access type it will be used is decided by where you put the #Id annotation (on the id field or the getId() method).