The Java POJOs that we create need not be composed solely of Primitive types. It is possible to group together value fields into Java classes. Such objects which exist as member fields inside the mapped java classes are called components.
Components are classes (or columns in the table) that do not have their own life-cycle.
They exist only as a part of the owning entity. If the Java Class is removed, then the component own its own does not exists. in UML terms there exists a composition relationship between the Components and the Java POJO (or Entity Class).
If the Entity remains,then the Component exists. The Entity does has its own (database) identity. The Component is owned by the Entity and does not have its own identity. Its persistent fields are actually the columns of the record representing the Entity in the database table. As it maps to within a single row, Components can only be associated with a single entity.
As stated earlier, the components can be used to group together similar data. e.g. The Person record may include a state, city and pin code field in its record. Rather than representing this data as individual columns in the Person class
Components are classes (or columns in the table) that do not have their own life-cycle.
They exist only as a part of the owning entity. If the Java Class is removed, then the component own its own does not exists. in UML terms there exists a composition relationship between the Components and the Java POJO (or Entity Class).
If the Entity remains,then the Component exists. The Entity does has its own (database) identity. The Component is owned by the Entity and does not have its own identity. Its persistent fields are actually the columns of the record representing the Entity in the database table. As it maps to within a single row, Components can only be associated with a single entity.
As stated earlier, the components can be used to group together similar data. e.g. The Person record may include a state, city and pin code field in its record. Rather than representing this data as individual columns in the Person class
class Person { private int id; private String name; //... private String city; private String state; private String zipcode; }
They could be grouped together as an address entity and placed within the person object.
class Address { private String city; private String state; private String zipcode; //... } class Person { private int id; private String name; private Address residence; //... }
This also provides us with a better way to represent multiple addresses if the need were to arise.
For my example I decided to create a component for auditing purposes. I have noticed in most applications that I have worked in, the Entities all include certain fields to help manage a minimum audit trail. These fields are generally of the form
For my example I decided to create a component for auditing purposes. I have noticed in most applications that I have worked in, the Entities all include certain fields to help manage a minimum audit trail. These fields are generally of the form
private Integer createdBy; private Date createdDate; private Integer modifiedBy; private Date modifiedDate;
The fields have no domain relationship with the rest of the Entity. They are a very good case of Value Types. Also they exist only for a single entity (i.e. within the same table row). These fields can be represented as components. The SQL code for one such Entity is as below.
create table USER ( ID int(11) not null auto_increment, NAME varchar(100) not null, Created_Date datetime default null, Modified_Date datetime default null, Created_By int(11) default null, Modified_By int(11) default null, PRIMARY KEY (ID) );The audit fields are present as columns in the row.The java Classes for this would be as below:
public class User { private Long id; private String name; private AuditField auditField; //setter getter for the component public AuditField getAuditField() { return auditField; } public void setAuditField(AuditField auditField) { this.auditField = auditField; }
//other setter-getters
}
public class AuditField { private Integer createdBy; private Date createdDate; private Integer modifiedBy; private Date modifiedDate; //setter-getter for the properties }
The mapping document is as follows:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.model"> <class name="User" table="USER"> <id name="id" type="long"> <column name="ID" /> <generator class="native" /> </id> <property name="name" type="string"> <column name="NAME" /> </property> <component name="auditField" class="com.model.component.AuditField"> <property name="createdBy" type="integer"> <column name="Created_By" /> </property> <property name="createdDate" type="timestamp"> <column name="Created_Date" length="19" /> </property> <property name="modifiedBy" type="integer"> <column name="Modified_By" /> </property> <property name="modifiedDate" type="timestamp"> <column name="Modified_Date" length="19" /> </property> </component> </class> </hibernate-mapping>
On executing the code to create a User record, the logs are as below:
static void testCreate() { Session session = SESSION_FACTORY.openSession(); Transaction transaction = null; final Date crtDate = new Date(); User user = new User(); user.setName("New User"); AuditField auditField = new AuditField(); auditField.setCreatedBy(1); auditField.setModifiedBy(1); auditField.setCreatedDate(crtDate); auditField.setModifiedDate(crtDate); user.setAuditField(auditField); transaction = session.beginTransaction(); Long id = (Long) session.save(user); System.out.println("New record is " + id); transaction.commit(); session.close(); }
765 [main] INFO org.hibernate.cfg.HbmBinder - Mapping class: com.model.User - > USER 765 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: id -> ID 781 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: name -> NAME 796 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: createdBy -> C reated_By 796 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: createdDate -> Created_Date 796 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: modifiedBy -> Modified_By 796 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: modifiedDate - > Modified_Date 796 [main] DEBUG org.hibernate.cfg.HbmBinder - Mapped property: auditField -> Created_By, Created_Date, Modified_By, Modified_Date ... 3078 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ver sion select: select ID from USER where ID =? 3078 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Sna pshot select: select user_.ID, user_.NAME as NAME0_, user_.Created_By as Created 3_0_, user_.Created_Date as Created4_0_, user_.Modified_By as Modified5_0_, user _.Modified_Date as Modified6_0_ from USER user_ where user_.ID=? 3078 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Ins ert 0: insert into USER (NAME, Created_By, Created_Date, Modified_By, Modified_D ate, ID) values (?, ?, ?, ?, ?, ?) 3078 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Upd ate 0: update USER set NAME=?, Created_By=?, Created_Date=?, Modified_By=?, Modi fied_Date=? where ID=? 3078 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister - Del ete 0: delete from USER where ID=? ... 3453 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedSt atement (open PreparedStatements: 0, globally: 0) 3468 [main] DEBUG org.hibernate.SQL - insert into USER (NAME, Created_By, Created_Date, Modified_By, Modified_Date) values (?, ?, ?, ?, ?) 3828 [main] DEBUG org.hibernate.pretty.Printer - listing entities: 3828 [main] DEBUG org.hibernate.pretty.Printer - com.model.User{id=1, auditFiel d=component[createdBy,createdDate,modifiedBy,modifiedDate]{createdBy=1, modified By=1, createdDate=2011-08-21 12:06:51, modifiedDate=2011-08-21 12:06:51}, name=N ew User}
As can be seen from the logs, the process of creating an Object with components is very similar to that of a simple Entity. The component mappings are read at start up. The SQL scripts generated for CRUD operations are very similar to that of non-component entities. I retrieved the same record back using a session.load call. The generated logs are as below
2578 [main] DEBUG org.hibernate.SQL -
select
user0_.ID as ID0_0_,
user0_.NAME as NAME0_0_,
user0_.Created_By as Created3_0_0_,
user0_.Created_Date as Created4_0_0_,
user0_.Modified_By as Modified5_0_0_,
user0_.Modified_Date as Modified6_0_0_
from
USER user0_
where
user0_.ID=?
2578 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - preparing statement
It is possible that the columns that map to the component do not have any value for a particular row. For e.g. the below code creates a User object with null values in the component fields.
User user = new User(); user.setName("New User with No Audit"); transaction = session.beginTransaction(); Long id = (Long) session.save(user);
The object is created successfully. If we retrieve the object then it will be found that the component field has a null value in the returned result. Hibernate will assume that if all component columns are null, then the entire component is null.
User user = new User(); user.setName("New User with No Audit"); transaction = session.beginTransaction(); Long id = (Long) session.save(user); System.out.println("New record is " + id); transaction.commit(); user = (User) session.load(User.class, 5L); //the component was received as null
//below statement will throw Null Pointer exceptions System.out.println("Name : " + user.getName() + "Date Created : " + user.getAuditField().getCreatedDate());
No comments:
Post a Comment