I have been following an excellent guide for generating pojos from a mysql database using hibernate. One can find the guide here for reference:
Generate pojos with hibernate
I am getting pojos which have fields that embed other objects when a foreign key was present. For example, user's have addresses. Hibernate is generating something like the following:
public class User(){
private String name;
private Integer uid;
private Address address;
}
I have a problem, though, in that I want the classes to actually contain the foreign key value. For example, I want the User object to have a class field corresponding to the database field for addressId. So, I want the object to actually look something like this:
public class User(){
private String name;
private Integer uid;
private Integer addressId;
private Address address;
}
Does anyone know how to modify the hibernate code generation process so as to include foreign key values as fields on the object?
Update:
I found a SO post which describes how to ignore the foreign key relationships and just get foreign keys as class fields: How to ignore foreign keys?
The problem here is that I want both. I don't want to ignore the relationships. I want them represented, but I also want the actual foreign key values.
Update:
Let me be more specific as to why I want this solution. We are trying to serialize these hibernate objects. Now, we have a lot of different hibernate pojos which are being reverse engineered. We do not want to manually write a serialization routine for every class. We would have to do that if we followed the convention of "just manually write an access method to the foreign key field on the embedded object". Further, even if we were to do so, the pojo still doesn't know what the field of the foreign key is called. Instead, we are using gson with a type adaptor.
With gson, we are serializing all fields on the pojo and just ignoring fields that contain a hibernate object. The problem, of course, is that we don't have the foreign key fields. We need a few pieces of information here in order to generically serialize any hibernate pojo. We need to know:
The foreign key field name
The foreign key field value
Your approach violates Hibernate convention. Because Hibernate uses reflection, convention is essential for Hibernate to do it's job. Because of this, I suspect Maouven's "follow the convention" approach is easiest. However, if it is non-negotiable, you have two options available.
Your first option is to add a transient getter, to expose the getAddressId() function.
public class User() {
private String name;
private Integer uid;
private Address address;
// Getters, setters...
#Transient
public boolean getAddressId() {
address.getId();
}
}
Your second option is to add a Data Access layer to impose your own conventions on top of Hibernate objects. This layer of abstraction will not be bound by Hibernate's conventions. This way, your POJOs will be wrapped by DAOs (Data Access Objects), which you can design as you see fit.
Update:
Given your unique case, consider modifying your serialization step. GSON normally can't use transient methods, but there is an extension that can do this, as shown here.
Another solution would be to use reflection to copy the object the way you want it, and then use GSON to serialize the copied object.
Your approach will cause redundancy in the class's data. In the first bunch of code -generated by Hibernate-, you can get the addressId you need from the Address property of the User Class :
yourUser.getAddress().getAddressId();
Two possible (theoretically speaking) solutions, but require manual refactoring after reverse engineering by Hibernate Tools:
I'm using annotations just for brevity
1) expose the column with mapping:
#Entity
class User
{
#Id
#Column
private Integer uid;
#Column
private String name;
#Column(name = "ADDRESS_ID", insertable = false, updatable = false)
private Integer addressId;
#ManyToOne
#JoinColumn(name = "ADDRESS_ID")
private Address address;
}
2) use #Transient + #PostLoad:
#Entity
class User
{
#Id
#Column
private Integer uid;
#Column
private String name;
#Transient
private Integer addressId;
#ManyToOne
#JoinColumn(name = "ADDRESS_ID")
private Address address;
#PostLoad
public void postLoad()
{
addressId = Optional.ofNullable(address).map(Address::getId).orElse(null);
}
}
Another solution could be possible using JSON marshaller for JAXB:
#XmlRootElement
class User
{
#XmlID
private Integer uid;
private String name;
#XmlIDREF
private Address address;
}
You can find a quickstart here
Related
I have an indexed entity, like below :
#MappedSuperclass
public static class Model{
#Id
#GeneratedValue(strategy=GenerationType.Identity)
private Integer id;
private boolean isDeleted;
}
and the indexed class is :
#Entity
#Table("USERS")
#Indexed
public class ProductModel extends Model{
#Field
private String name;
//getters & setters
}
Well, when I do a research on ProductModel, I get the value of the flag isDeleted while its not annotated with #Field.
I'm asking if this is a normal behavior, does Hibernate-search Index the whole Object Or does it fetch the missing data from data base, I need an explanation for this behavior please.
Hibernate Search only stores in the index the fields you declare explicitly (more precisely, it indexes by default and you can ask Hibernate Search to store it by adding the store option to your #Field annotation).
What you observe is that Hibernate Search hydrates the objects with the information of the database after having performed the search. This is one of the main interest in using Hibernate Search: the objects returned are managed entities.
Let's say that this is a class that has unique constrained field.
#Entity
public class Thing {
#Column(name = "name", unique = true)
private String name;
#ManyToOne
private Owner owner;
}
Example works just fine if new Things are created with unique names. But when different owners want to create things with the same name this approach fails.
Is it possible to set unique constraint to differ records of Things in the database based on the Owners using Hibernate/JPA functionalities (I could not find any) or should I write my own logic and dump the unique from #Column.
Perhaps it could be done with Hibernate Validator? Reading the docs I haven't found much about unique constraints.
You're looking for #UniqueConstraint
http://docs.oracle.com/javaee/5/api/javax/persistence/UniqueConstraint.html
How can I implement my unique constraints on the hibernate POJO's? assuming the database doesn't contain any.
I have seen the unique attribute in #Column() annotation but I couldn't get it to work?
What if I want to apply this constraint to more than one column?
You can declare unique constraints using the #Table(uniqueConstraints = ...) annotation in your class
#Entity
#Table(uniqueConstraints=
#UniqueConstraint(columnNames = {"surname", "name"}))
public class SomeEntity {
...
}
Bascially, you cannot implement unique constraint without database support.
#UniqueConstraint and unique attribute of #Column are instructions for schema generation tool to generate the corresponsing constraints, they don't implement constraints itself.
You can do some kind of manual checking before inserting new entities, but in this case you should be aware of possible problems with concurrent transactions.
Therefore applying constraints in the database is the preferred choice.
In JPA2, you can add the Unique constraint directly to the field:
#Entity
#Table(name="PERSON_TABLE")
public class Person{
#Id
#Column(name = "UUID")
private String id;
#Column(name = "SOCIALSECURITY", unique=true)
private String socialSecurityNumber;
#Column(name = "LOGINID", unique=true)
private String loginId;
}
IMHO its much better to assign the unique constraint directly to the attributes than at the beggining of the table.
If you need to declare a composite unique key however, then declaring it in the #table annotation is your only option.
Given the following example (departments - projects):
A department has the following properties (composite primary key):
#Entity
#IdClass(DeptId.class)
public class Department
{
#Id
#Column(name="number")
private Integer number;
#Id
#Column(name="country")
private String country;
#Column(name="name")
private String name;
#OneToMany(mappedBy="dept")
private Collection<Project> projects;
...
}
Here the PK class:
public class DeptId implements Serializable
{
private Integer number;
private String country;
...
}
The relationship between projects and departments is many-to-one, that is a deptartment can have many projects. The Project class is itself using a composite key referencing Department's composite key. Important note: it's only about the implementation with #IdClass not #EmbeddedId.
Then the (problematic) JPA 1.0 #IdClass implementation would have to look something like that (redundant deptNum and deptCtry properties): -> it's just a unique name within a department
#Entity
#IdClass(ProjectId.class)
public class Project
{
#Id
#Column(name="dept_number")
private Integer deptNumber;
#Id
#Column(name="dept_country")
private String deptCountry;
#Id
#Column(name="name")
private String name;
#ManyToOne
#JoinColumns({
#JoinColumn(name="dept_number", referencedColumnName="number"),
#JoinColumn(name="dept_country", referencedColumnName="country")
})
private Department dept;
...
}
The ProjectId is:
public class ProjectId implements Serializable
{
private String name;
private DeptId dept;
...
}
The problem with this is that neither Hibernate nor EclipseLink know how to map the two redundant properties deptNum and deptCtry in Project to the dept property in DeptId (or the properies within it). -> MappingException etc.
My question is:
Is this a limitation of JPA 1.0, that tables with composite keys referencing other composite keys with #IdClass implementations generally WON'T work, because the JPA implementation simply can't know how to map these fields?
As a workaround, you'd have to use #EmbeddedId for these classes or use JPA 2.0 syntax to annotate the #XToX associations with #Id. I just want to make sure my view on this is right.
Thanks
Yes, this is a limitation of JPA 1.0, corrected in JPA 2.0. In the new JPA 2.0, you can put the ID annotation on your dept relationship and completely avoid having the redundent deptCountry and deptNumber attributes, with the key class using nesting. In JPA 1.0, only basic mappings can be marked as apart of the ID, requiring redundent mappings and some code to ensure that the values/relationships get put into the cache correctly when persisting. Because of the redundancy, as mentioned in other answers, one of the mappings for a field needs to be marked read-only via the insertable/updatable=false. Doing so though means that value is not merged into the cache - so changes (such as on insert, since you can't change an objects ID once it exists) will not be reflected unless the object is refreshed from the database. If you mark the JoinColumns as read-only, you will need to get the values from the referenced dept and put them into the correspoinding basic id attributes manually when you want to persist a Project. But, you can also mark the basic attributes as read-only. Eclipselink anyway will not have any problems and will correctly set the field values using the associated dept entity (as long as it is set before persist is called on the Project). Notice though that the basic attributes may or may not be populated when you read back the project in a different context- this will depend on if the entity is refreshed from the database or not. If they are read-only, they do not get merged into the shared cache since they, being read only, should not have changed. So they can be just ignored, or if they must be populated, the entity refreshed or the values set from the dept in an event.
This same model can be reused by using the JPA2.0 #MapsId, which will also maintain the basic mappings using the values from the relationship for you. Only benifit I see is that you don't need to access the relationship (potentially causing unneccessary joins or database access on lazy relationships) to get the foreign key/id field values.
As for the ZipArea EclipseLink exceptions, they are due to ZipAreaId having a ZipId zip attribute instead it being flattened out. JPA 1.0 requires the key class to have an attribute of the same type and name for each #ID attribute in the Entity.
The problem with this is that neither Hibernate nor EclipseLink know how to map the two redundant properties deptNum and deptCtry in Project to the dept property in DeptId
This is why you need to define the ManyToOne foreign key(s) as read-only with this kind of mapping. This is done by setting the JoinColumn attributes insertable and updatable to false.
So try the following:
#Entity
#IdClass(ProjectId.class)
public class Project
{
#Id
#Column(name="dept_number")
private Integer deptNumber;
#Id
#Column(name="dept_country")
private String deptCountry;
#Id
#Column(name="name")
private String name;
#ManyToOne
#JoinColumns({
#JoinColumn(name="dept_number", referencedColumnName="number", insertable=false, updatable=false),
#JoinColumn(name="dept_country", referencedColumnName="country", insertable=false, updatable=false)
})
private Department dept;
...
}
The problem with the posted code is, that JPA 1.0 really doesn't allow nesting of composite primary key classes. This ProjectId is invalid:
public class ProjectId implements Serializable
{
private String name;
private DeptId dept;
...
}
DeptId has to be flattened, like:
public class ProjectId implements Serializable
{
private Integer deptNumber;
private String deptCountry;
private String name;
...
}
I just got an EclipseLink version to go, but Hibernate has problems with that. I wonder how to tell Hibernate that JPA 1.0 is assumed.
I want to insert and retrieve a a user defined Object in DB,am using Mysql5.1.
1)What should me the data type for the column(is Blob is the correct answer for this question)
I am using EntityClass to Insert/Get values from the DB.
2)but to how to insert Object in database?
The common way is to translate the object to a table - every field of the object is (toughly) translates to a column of the table. The term for this is object relational mapping. There is plenty of documentation of this on the web (like this) as this is one of the cornerstones of modern day enterprise development.
There are several libraries you can use, and the best is to stick to the standard called JPA - Java Persistence API. The most known libraries (all open source) are
Hibernate
EclipseLink
OpenJPA
Your user defined object will look like this :
#Entity
#Table(name = "some_table")
public class SomeObject implements Serializable {
static final long serialVersionUID = <some value>;
#Id
#GeneratedValue
protected Long id;
#Column
protected String name;
#Column
protected int value;
// default constructor
// getters, setters
// equals, hashCode, toString
// other methods
}