I have tried omitting the #Embedded annotation and still the fields have been embedded in the table. I cannot find anything which would say that the #Embedded annotation is optional.
Is it or is it not optional?
The following code
#Embeddable
public class Address {
String city;
String street;
}
#Entity
public class Person {
String name;
#Embedded // it seems that it works even if this annotation is missing!?
Address address;
}
generates always the same table
person
name
city
street
even if I do not specify #Embedded.
My configuration:
JBoss EAP 6.4.0
hibernate-jpa-2.0-api-1.0.1.Final-redhat-3.jar
The JPA specification says:
http://docs.oracle.com/javaee/7/api/javax/persistence/Embedded.html
#javax.persistence.Embedded
Specifies a persistent field or property of an entity whose value is an instance of an embeddable class. The embeddable class must be annotated as Embeddable.
http://docs.oracle.com/javaee/7/api/javax/persistence/Embeddable.html
#javax.persistence.Embeddable
Specifies a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entity.
In case of using Hibernate it does not matter if you annotate the field itself (as #Embedded) or if you annotate the referenced class (as #Embeddable). At least one of both is needed to let Hibernate determine the type.
And there is a (implicit) statement about this inside the Hibernate documentation, take a look here:
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#mapping-declaration-component
It says:
The Person entity has two component properties, homeAddress and
bornIn. homeAddress property has not been annotated, but Hibernate
will guess that it is a persistent component by looking for the
#Embeddable annotation in the Address class.
Embedded-Embeddable is not mandatory, but it gives you nice OOP perspective of your entities' relationship. Another way to do such a thing - is to use OneToOne mapping. But in such a case entity WILL be written to separate table (while in case of embedded it CAN be written to the separate table in your DB).
Related
I am trying to create a entity class using Java record, but I get the error message
"Entity does not have primary key" although I assigned an ID annotation.
import javax.persistence.*;
import java.time.LocalDate;
#Entity
public record Agent (
#Id
String code,
String name,
LocalDate date,
String workingArea,
String country,
String phoneNumber,
boolean licenseToKill,
int credits,
byte[] picture)
{}
What's wrong with this?
A record cannot be used as Hibernate entity because it breaks the requirements of an entity according to JPA specification. Make it class and use #Immutable annotation instead:
#Entity
#Immutable
public class Agent
Just clearing the answer for completeness (although #Turning85 and #gkatiforis have already provided correct explanation):
According to the JPA specification, an entity must follow these requirements:
the entity class needs to be non-final,
the entity class needs to have a no-arg constructor that is either
public or protected,
the entity attributes must be non-final.
However, as explained by this article, the Java Record type is defined like this:
the associated Java class is final,
there is only one constructor that takes all attributes,
the Java record attributes are final.
But records are a good fit for a DTO projection, which is often used as a read-only representation of the data stored in your database.
more info - https://thorben-janssen.com/java-records-hibernate-jpa/
I have same-named field (int phone;) both in my entity class and in the embedded class. As per JPA Specification I shall use #AttributeOverrides in my entity over the embedded field.
The logic behind that: fields of embedded class are saved to the same database table as fields of entity class itself (loosely speaking adding one embedded filed to entity class looks like just adding all fields of the embeddable class to that entity), and thus we have two fields with the same default name for a respective column of the table used to store the entity in the database.
But what if I specify #Column(name="alternative_phone_name") either on the filed of Embeddable class, or on the filed of the Entity class - in such case there is no conflict and no #AttributeOverrides is necessary? Right? This is my question.
Secondly, what happens if I specify #Column(name="alternative_phone_name") on the filed of Embeddable class and then also redefine it with #AttributeOverrides over the embedded field inside the entity class? Is it an error and what would the database column name be in that case?
#Embeddable
class MyEmbeddable {
#Column(name="my_embed_phone")
int phone;
}
class MyEntity {
int phone;
// 1) do I need
// #AttributeOverrides({
// #AttributeOverride(name="phone", column="sth_different_than_phone")
// })
// 2) If I don't need it, would specifying it is error?
// Which overrides - this #AttributeOverrides or MyEmbeddable's #Column(name=...
#Embedded
MyEmbeddable embeddedFld;
}
For example, I have an entity below.
#Entity
public class Indexer
#NotNull #Id
private long id;
#Column
private string volumeKey;
}
I want to create a table with a ‘volumeKey’ property in this entity.
For example, A indexer has a ‘X12372’ as a volumeKey of property. I want this entity to be mapped to ‘INDEXER_X12372’.
And I tried to create custom NamingStrategy class for Indexer. And I can’t get an entity to be mapped in this class for making a table of name from.
You want the table to be used to be determined by a value of a property.
This is not possible with JPA or Spring Data JPA.
But some (many?) databases can do this transparently with partitioned tables.
See https://docs.oracle.com/cd/B28359_01/server.111/b32024/partition.htm for Oracle documentation as an example.
It should be easy enough to find a similar document for the database you use.
Could be possible change the name of the Entity variable ID in JPA? Currently, the DAO save method use the Entity ID.
We have multiple existing tables in our database and then, we will have to add the ID column to all tables. Is there any way I can avoid adding the fields?
I suppose one possibility will be to override the DAO methods, but any other ideas?
Thanks in advance.
So your entity is defined as:
#Entity
public class SomeEntity {
#Id
private Integer id;
//...
}
You don't have to name the variable id unless you really want to. You could name this someEntityId and JPA nor Hibernate cares. The only influence the property name will have is how the NamingStrategy implementation will map that to a column name in the database.
We can override the naming strategy and apply specific names to columns if we need where cases exist that the naming strategy doesn't work for us.
#Id
#Column(name = "some_entity_id")
private Integer id;
This essentially will map the id variable to a column named some_entity_id.
Hope that helps.
I have Person entity which has composition with Location Entity
#ManyToOne(fetch = FetchType.EAGER, cascade =
{ CascadeType.PERSIST, CascadeType.MERGE })
#Cascade(
{org.hibernate.annotations.CascadeType.SAVE_UPDATE })
public Location getLocation()
{
return location;
}
And Location Entity has Name as Id
#Id
public String getName()
{
return name;
}
I am getting following Exception when Person's location is changed from L1 to L2 in Spring MVC form where this Person entity is modelAttribute for the form.
org.springframework.orm.hibernate3.HibernateSystemException:identifier of an instance of com.x.y.z.Location was altered from L2 to L1; nested exception is org.hibernate.HibernateException: identifier of an instance of com.x.y.z.Location was altered from L2 to L1
You're confusing Composition with Association.
What you have mapped is an association; composition in Hibernate (JPA) is mapped via #Embeddable / #Embedded annotations. Associations are relationships between separate entities; they are usually connected via entity identifiers (foreign keys in the database).
In your particular case, Person entity points to Location entity which means in the database PERSONS table has a LOCATION_ID foreign key (names may differ) to LOCATIONS table. What you're trying to do is to update that key on Location end which is illegal because it would sever Hibernate's relationship (the other end still holds the previous key value internally).
Primary keys should generally be surrogate and not updatable to begin with; if you do need to "update" it you'll have to either disassociate Location from Person, update Location and assign it to Person again OR create a brand new Location instance and assign that to your Person.
All that said, if you're really trying to model Composition relationship, you need to replace #ManyToOne with #Embedded and change your table schema accordingly. Here's a link to
Hibernate Annotations documentation on mapping components.
Also, specifying cascade types in two separate annotations (JPA vs Hibernate extension) is not a good thing. If you really need the Hibernate extension one (which you don't in this case), just use it and leave cascade attribute in JPA annotations empty.
I done same thing in standalone application . The thing works. I think it should be some problem with #modelAttribute.
In your Location entity attribute id type has been changed in your model class.Please refer the id and mapping attribute id types are same.Make sure that id attribute getter and setter function return types.