I'm currently studying the official JPA 2 final specification.
Is the following statement contained anywhere in the Spec?
The Entity Manager guarantees that within a single Persistence Context,
for any particular database row, there will be only one object
instance.
Either I don't clearly understand the spec or I just can't find the part that proves that the quoted statement is part of the specification.
No, specification does not give such a guarantee. But in my opinion it is implicitly assumed.
In practice sometimes same table is mapped to the two different entities. One of them being treated as read only entity. Read only entity can for example be used for reporting purposes and as an optimization contains only subset of fields in other entity. This can be done for example as follows:
#Entity
public class EntityA {
#Id private Integer id;
#Lob
byte[] tooHeavyToLoadAlways;
}
#Entity
#Table(name="EntityA")
public class EntityALightWeight {
#Id private Integer id;
}
For JPA there is no connection between these two entities, so keeping care that only first one of them is modified and that second one is refreshed is responsibility of application. Because of that should be used only with caution, because EntityALightWeight can be refreshed from database but will never contain changes made to the EntityA in same transaction.
Related
Let's say we have such classes in the Java project:
#Entity
class Person {
#Id
String internalId;
#OneToMany
Set<Profession> profession;
}
#Entity
class Profession {
#Id
String id;
String professionName;
Integer yearsOfPractise;
}
In the business logic the professionName has to be unique per Person.
Is it correct to #override the equals with taking into the account only the professionName field and ingoring the others?
On the one hand such the equals can be handy if this class is handled from the business logic perspective. But such equals can be completely wrong and unhandy in cases when this class will have to be handled from some different perspective.
How to decide it?
Of course, this way you are using a business id, instead of the one that is probably generated by the jpa vendor and as a result, entities, that are manages are equal to the same that aren't.
For example if we create an entity, where the id is generated by the database and save it, the following gives no error:
Entity entity = new Entity();
Entity savedEntity = entityRepository.save(entity); // CrudReporitory
assertFalse(entity.equals(savedEntity));
In most cases it's not what we want. For more details I recommend this article.
You can overide the equals according to your business logic. In my case, I have excluded id.You can modify which fields are used with the lombok library:
https://projectlombok.org/features/EqualsAndHashCode
For Example:
#EqualsAndHashCode(exclude = "id")
public class Foo {
private Integer id;
}
Since, there are two cases:
comparing two entities by equality (content)
comparing two entities by an identifier
You should not override equals to do either or. This would be confusing. Instead use a dedicated function for each. This way you/or anyone else reading the code can choose the correct one and this choice will be obvious to the reader.
I need to create a database with 2 kinds of 'modules'.
domain focused classes
metadata classes
In the first group it is just simple (or complex rather) RDBMS. The second 'block' are metadata classes which collects information about classes from the first block.
What I have done:
Created Entity class which is parent of all fro 1st part:
#PersistenceAware
#Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public abstract class Entity implements Serializable {
private static final long serialVersionUID = 1L;
}
Created normal schema with all entities inherit somehow Entity class.
Created InternalMapping class as a parent of the whole concept.
#PersistenceCapable
#Inheritance(strategy = InheritanceStrategy.NEW_TABLE)
public abstract class InternalMapping implements Serializable {
private static final long serialVersionUID = 1L;
private Entity entity;
//.. cut off getter and setter
}
Created InternalMapping child which should have that feature.
Finally I found it does not work. Probably because Entity does not have any field. But if so I would expect 2 fields: a primary key and class name. In that way I would map every entity by 2 coordinates: ID and class name.
Any idea how to solve that issue? An finally how JDOQL would looks like.
Ps. I know that RDBMS is not the best solution for that kind of problems but people with whom I work wish to have relational database.
Finally I found solution for my problem. I am able to keep entities of different classes keep in one table. Also I am able to do JDOQL request with filtering instances of particular class.
The example is inside GitHub repository here: https://github.com/jgrzebyta/samples-jdo/tree/metalink and within metalink branch. It is slightly modified Tutorial project from datanucleus example.
So.
The lowest level in the inheritance hierarchy is Core interface with the PK defined inside.
Class MyIndex collects different implementations of the Core interface, i.e. Book and Product. Also I have added new column called type for storing Class names only. I am able to retrieve implementations of Core interface and build query filter against type filed because query type core instanceof Book simple does not work. That is the feature of the identity mapping strategy which I have used in my solution: DataNucleus JDO Objects.
PS. If you run command mvn -Pschema-gen compile than you will receive DDL file.
What is the difference between #Embedded annotation technique and #OneToOne annotation technique because in Embedded the java class contain "Has a" relationship in class and with the help of #Embedded annotation we persist the has a object in database. and in OneToOne relationship we also persist the has a object in database.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. For example a Customer might always have one record in a Name table.
Alternatively if those name fields are on the Customer table (not in a separate table) then you might want an #embedded. On the face of it you could just add the name fields as standard attributes to the Customer entity but it can be useful if those same columns appear on multiple tables (for example you might have the name columns on a Supplier table).
Its the difference between composition and aggregation. #Embedded objects are always managed within the lifecycle of their parents. If the parent is updated or deleted, they are updated or deleted as well. #OneToOne objects may mimic composition via the cascadeType option of their #Join annotation, but by default they are aggregated, aka their lifecycle is separate from that of their parent objects.
#Embedded is used with Value Objects (Objects which have a meaning only when attached to an Object) whereas one to one mapping is between two objects having their own existence and meaning.
For e.g.
Value Object and #Embedded: If we have a User class and this class has an address Object in it, it can be considered as a value object as the address alone does not have any significance until unless associated with a user. Here address object can be annotated with #Embedded.
One to One mapping and #OneToOne: If we have a User class and this class has a 'Father' Object or a 'Mother' object, we would want to annotate the 'Father' or 'Mother' instance as #OneToOne as 'Father' or 'Mother' have their own meaning and existence and are not Value objects to User class.
A closely related difference is between #OneToMany and #ElementCollection. Both are used to save instance variables of Collection type in Java class. The difference being, #ElementCollection is to be used when the elements of Collection being saved are Value Objects whereas #OneToMany is used when the elments and object have well defined meaning and existence.
Use #OneToOne, only if fields can be reused. Otherwise, go for #Embeddable.
A quote from Beginning Hibernte, 3rd Edition:
There is nothing intrinsically wrong with mapping a one-to-one association between two entities where one is not
a component of (i.e., embedded into) the other. The relationship is often somewhat suspect, however. You should
give some thought to using the embedded technique described previously before using the #OneToOne annotation.
#Embeddable:
If the fields in an entity (X) are contained within the same table as another entity (Y), then entity X is called "component" in hibernate terms or "embedded" in JPA terms. In any case, JPA or hibernate do not allow to use 2nd table to store such embedded entities.
Generally, we think of normalizing a table when data is being reused by more than one table. Example: A Customer (id, name, street, city, pin, landmark) can be normalized into Customer(id, name) and CustomerAddress(cust_id, street, city, pin, landmark). In this case, we can reuse CustomerAddress by linking the same using cust_id with other tables. But if this reuse is not required in your application, then we can just keep all columns in one table.
So, a thumb rule is,
If reuse -> #OneToOne,
If no reuse -> #Embeddable
#Embedded is typically to represent a composite primary key as an embeddable class:
#Entity
public class Project {
#EmbeddedId ProjectId id;
:
}
#Embeddable
Class ProjectId {
int departmentId;
long projectId;
}
The primary key fields are defined in an embeddable class. The entity contains a single primary key field that is annotated with #EmbeddedId and contains an instance of that embeddable class. When using this form a separate ID class is not defined because the embeddable class itself can represent complete primary key values.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. #Id will be the primary key.
Is there a possibility in JPA 2.0 to asure that an embedded object is embedded with only one object, but not several?
In my case I have an Address that I can assign to a Customer. I want every customer to use its own address object and would like to create a constraint that makes sure that no two customers share the actually same object.
My code looks like this:
#Entity
public Customer {
#Id
#GeneratedValue
private Long id;
#Embedded
private Address address;
// ..
}
#Embeddable
public Address {
private String street;
private String city;
// ..
}
Currently, if I create two customers and assign them the same Address object, then persist and read them, they again share the object with the same identity. I want to prohibit saving such customers that share addresses with other customers.
The simpliest approach in this case is to create a copy of Address object in Customer.setAddress().
Also, I'm not sure that different Customers can share Address with the same identity when retrieved from the database. Perhaps you get the same objects from the session cache because you save and read them in the same session.
It is the nature of the #Embedded mechanism that embedded instances of an embeddable class are NEVER shared among different instances of the enclosing class. If you observed this behavior in your code, it must have been because you were accessing cached data during reading from the entity manager.
So, even if you assign the same instance of an embeddable class to multiple instances of the enclosing class, then "persist()", then destroy the entity manager and EntityManagerFactories, or invalidate the caches "entityManager.getEntityManagerFactory().getCache().evictAll()", then create a new EntityManager and "find()" the enclosing objects, each of them should have their own instance of (in your case) "Address" objects, even if their content is the same.
The JPA spec says the following about embedded objects in section 2.5:
[...] Instances of these classes, unlike entity instances, do not have
persistent identity of their own. Instead, they exist only as part of
the state of the entity to which they belong. [...]
If your JPA implementation doesn't adhere to that, it isn't really JPA standards-compliant...
Does Hibernate have an API for reading the value of an entity's identity field? In my case, this would be the Serializable value returned by the field annotated with #Id. For example, suppose I had a Person entity:
class Person {
#Id private long id;
// ... other fields, getters/setters, etc ...
}
Person p = new Person();
p.setId(42L);
Hibernate.unknownFunction(p); // returns 42L
Sure I could read the annotations to find the #Id field myself, but this seems like something that might be built in.
session.getIdentifier(object)
Return the identifier value of the given entity as associated with this session. An exception is thrown if the given entity instance is transient or detached in relation to this session.
The object needs to have an ID, and to be associated with the current session, otherwise an exception is thrown. But that is logical, I think.
Well, if you need a method that return id in arbitrary classes, design a interface to satisfy this. for example:
public interface IdHolder {
Integer getId();
}
With such interface, you could make some utility methods to retrive id from arbitrary classes.
The cglib is a robust but a bit of tricky way to do it.
I can't say 100% no - but I really doubt it since not all Entities are annotated with #Id; there are other variants that can be used such as #EmbeddedId. Given this, can't you just use reflection to get at your id value?