I'm currently coming (back) up to speed with EJB and while I was away it changed drastically (so far for the better). However, I've come across a concept that I am struggling with and would like to understand better as it seems to be used in our (where I work, not me and all the voices in my head) code quite a bit.
Here's the example I've found in a book. It's part of an example showing how to use the #EmbeddedId annotation:
#Entity
public class Employee implements java.io.Serializable
{
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name="lastName", column=#Column(name="LAST_NAME"),
#AttributeOverride(name="ssn", column=#Column(name="SSN"))
})
private EmbeddedEmployeePK pk;
...
}
The EmbeddedEmployeePK class is a fairly straightforward #Embeddable class that defines a pair of #Columns: lastName and ssn.
Oh, and I lifted this example from O'Reilly's Enterprise JavaBeans 3.1 by Rubinger & Burke.
Thanks in advance for any help you can give me.
It's saying that the attributes that make up the embedded id may have predefined (through explicit or implicit mappings) column names. By using the #AttributeOverride you're saying "ignore what other information you have with regard to what column it is stored in, and use the one I specify here".
In the UserDetails class, I have overridden homeAddress & officeAddress with Address
This One Address POJO will act for two table in DB.
DB:
Table1 Table2
STREET_NAME HOME_STREET_NAME
CITY_NAME HOME_CITY_NAME
STATE_NAME HOME_STATE_NAME
PIN_CODE HOME_PIN_CODE
The EmbeddedEmployeePK class is a fairly straightforward #Embeddable class that defines a pair of #Columns: lastName and ssn.
Not quite - EmbeddedEmployeePK defines a pair of properties, which are then mapped to columns. The #AttributeOverride annotations allow you to override the columns to which the embedded class's properties are mapped.
The use case for this is when the embeddable class is used in different situations where its column names differ, and some mechanism is required to let you change those column mappings. For example, say you have an entity which contains two separate instances of the same embeddable - they can't both map to the same column names.
JPA tries to map field names to column names in a datasource, so what you're seeing here is the translation between the name of a field variable to the name of a column in a database.
You can override also other column properties (not just names).
Let's assume that you want to change the length of SSN based on who is embedding your component. You can define an #AttributeOverride for the column like this:
#AttributeOverrides({
#AttributeOverride(name = "ssn", column = #Column(name = "SSN", length = 11))
})
private EmbeddedEmployeePK pk;
See "2.2.2.4. Embedded objects (aka components)" in the Hibernate Annotations documentation.
In order to preserve other #Column properties (such as name and nullable) keep them on the overridden column the same as you specified on the original column.
Related
I am looking for an answer if it is possible or not in hibernate. What I am trying to achieve is that if a field exists in a particular table then only it should insert it. Else just ignore the field in the #Entity class.
I want this as a new field is going to introduce in one of the table we are using and there are many dependent components which right now insert the data into that table. I don't want a big bang release. Want something like it doesn't impact the older version as well as when the upgrade happens and a new column introduced then also it should work.
For example -
#Entity
#Table(name = "EMPLOYEE_RECORDS")
public class Employee
{
#Id
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "employee_name")
private String employeeName;
#Column(name="address")
private String address;
}
What if I only want to insert address field into DB only when column(address) exists in the table EMPLOYEE_RECORDS. Please forgive me if this is something obvious, as I am not very proficient in Hibernate.
Also let me explain what have I thought of (But not sure if it will also work) -
1. Create 2 different #Entity classes. Try to insert and if the insertion failed then at runtime switch the #Entity and use without address.
2. Check if field exist in the table by simple query if it fails use #Entity without address else use without address.
I'm very confused about the scenario - It seems like there were deeper issues regarding decoupling of components in your system.
Nevertheless, you can add the column in the database, but you don't need to declare the field in the hibernate entity. On the other hand there is no way you can have an optional field in an hibernate entity. Either a field is mapped or it is not mapped.
I'm designing a solution for dealing with complex structure (user related stuff with lots of relations) in a simplier and possibly more efficient way than getting all the related data from DB. The only part of data I really need in my use case is basically contained withing the non-relational 'main' entity fields.
As for now I extracted the basic fields from 'main' class (let it be class OldMain) to another class (let's call it abstract class Extracted), used #MappedSuperclass and created 2 classes that extends it- Basic (which is empty class as Extracted gives it all the data I need and mapped to table 'X') and Extended (which is also mapped to table 'X' but with all the extra relations). It basically works but the code structure looks odd and makes me thinking if that's a proper way of dealing with such a problem.
I also tried with lazy initiation on relational fields (which i guessed on the beginning would serve here well), but I wasn't able to get it to work as I wanted with Jackson (only non-lazy fields in JSON, without fetching lazy related data- it couldn't be serialized or fired another several dozen of relation queries).
Another thing i stumbled upon in some tutorial was making DTO from 'OldMain' entity to not touch the lazy fields but haven't tried it yet as I started with the #MappedSuperClass way.
#Table(name = "X")
#MappedSuperclass
public abstract class Extracted{
//all the non-relational fields from OldMain
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String surname;
private String userName;
private String email;
}
#Table(name = "X")
#Entity
public class Basic extends Extracted{
//empty
}
#Table(name = "X")
#Entity
public class Extended extends Extracted{
//all relational fields from OldMain, no data fields
}
Also the general question is- is there any good practices when dealing with need of using only a subset of a bigger entity?
There is no obligation for a JPA Entity to map all existing columns in the corresponding table in the database. That is, given a table my_entity with columns col1, col2, col3, the Entity mapped to this table could map only col1 and col2 and ignore col3. That being said, plus the fact that you only need the non-relational attributes, you could directly use your Extracted class with the attributes you need and ignore the fact that other relational field exists. Furthermore, if all the relational fields are nullable then you could even be able to persist new instances of Extracted class. And Jackson would only (un)marshal the declared attributes in Extracted class.
In other case, I suggest to follow the approach you already are in and define new Entity classes that extend your Extracted class with the required attributes. I don't see how "code structure looks odd", other than having a Basic class with no new attributes than Extracted - you could easily make Extracted non-abstract and use it directly, and get rid of Basic.
Am i right that #Id annotation add two constraints in database:
nullable=false
unique=true
?
I saw a lot of examples in the Internet with syntax like
#Id
#Column(name="xxx",nullable=false)
BigInteger id
It is correct? Do i really need this nullable=false?
Yes you are right. If you use hibernate schema generation mechanism, all #Id columns in the database will be NOT NULL and have unique index by default.
In the other hand, #Column(nullable=false) declaration is absolutely meaningless if you create the schema any other way.
One reason you might see the two together is for the name attribute on #Column. It's name attribute lets you explicitly choose the name of the column in the resulting table, in cases where the default name that JPA provides. I will at times use #Column solely for that purpose, just so I can give my column a certain name.
As for the nullable attribute, I agree with you. It's worthless in that case.
How does the Embedded annotation affect the database?
How will SQL queries need to change?
What's the typical usecase for using the annotation?
How does Embedded annotation affect the database?
It does not affect it at all. On ORM provider layer all fields from embedded entity are merged with parent entity and treated the same as if they were declared there all the time. In other words it works as if you would literally copy all the fields, getters and setters into the entity that contains embedded object.
How will SQL queries need to change?
They won't. You don't need to change anything. See above.
What's the typical case for using the annotation annotation?
Sometimes you have a huge table with several columns (especially with legacy databases). However some columns are logically tied to each other (like street, city and phone number in CUSTOMER table). When you don't want to create an object with all the fields, you create an embedded Address object. This way you logically group address columns into an object instead of having equally huge POJO with a flat list of fields.
Using embedded objects is considered a good practice, especially when strong 1-1 relationship is discovered.
extending the answer of #Tomasz Nurkiewicz Embedded objects are useful to mapping a table's with a composite primary key whit help of the annotation #EmbenddedId
What's the typical usecase for using the annotation?
This 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.
How does the Embedded annotation affect the database?
It does not. Use this annotation to represent a composite primary key.
How will SQL queries need to change?
They won't.
Like Tomasz said - that's the one goal - the other - you can "snaphot" the state of other related entity inside your table.
F.e.
#Embeddable public class Company {
String name;
String streetName;
String city;
}
#Entity public class Invoice {
#Embedded
#AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="name")),
#AttributeOverride(name="streetName", column=#Column(name="streetName")),
#AttributeOverride(name="city", column=#Column(name="city")),
})
Company seller;
#Embedded
#AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="name")),
#AttributeOverride(name="streetName", column=#Column(name="streetName")),
#AttributeOverride(name="city", column=#Column(name="city")),
})
Company customer;
}
in this example - without embedded and #AttributeOverrides any change in future of Company customer will change the data in Invoice - which is a bug - the invoice was generated for the company with old data.
It's good explained here: :)
Java - JPA #Basic and #Embedded annotations
It doesn't always have to be the ID of the class. In Domain Driven Design, you can create a component out of some of the properties of an object, e.g. in this example http://yaarunmulle.com/hibernate/hibernate-example/hibernate-mapping-component-using-annotations-1.html a student has an address component.
The Address property of Student is annotated with #Embedded to point to the Address class component.
Are there any statements in JPA spec or official docs about certain JPA implementations which describe the behavior when we annotate entity's methods and when we annotate entity's fields?
Just a few hours ago I met an ugly problem: I use JPA (via Hibernate, but without anything Hybernate-specific in java code) with MS SQL Server. And I put all annotations on entities' fields (I preferred this style until this day).
When I looked at the DB I found that all table columns which should be foreing keys and which should contain some integers (ids) in fact had varbinary(255, null) type and contained hashes of something (I don't know what was that but it looked as a typical MD5 hash).
The most frustrated thing is that the app worked correctly. But occasionally (on updates) I got MS SQL exception which stated that I tried to insert too long values and data cannot be truncated.
Eventually (as an experiment) I removed all annotations from entities fields and put all of them on methods. I recreated DB and all tables contained perfect FK column. And those columns stored integers (ids, like 1, 3 ,4 ...).
So, can somebody explain what was that?
I've found this SO thread and it's accepted answer says that the preferred way is to put annotations on fields. At least for my concrete case I can say that it's not true.
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).
From experience, I do the following.
I put the entity details at the top of the entity class definition, (schema, row constraints, etc) for instance....
#Entity
#Table(name="MY_TABLE", schema = "MY_SCHEMA", uniqueConstraints = #UniqueConstraint(columnNames = "CONSTRAINT1"))
For the fields defined, I do not put the annotations on the field declarations, but rather on the getter methods for those fields
#Column(name = "MY_COL", table="MY_TABLE", nullable = false, length = 35)
public String getMyCol() {
return this.myCol;
}
public void setMyCol(String myCol) {
this.myCol = myCol;
}