Hibernate - POJO and HBM file creation best practice

(2008年08月07日)发表于[Technorati] Tag results for java
Recently I was working on Hibernate and created a number of POJO and their corresponding hbm file. I am using Netbeans (who has support for Hibernate plugin , real helpful , http://netbeans.org ) Certain best practice I would like to make work more interesting. Keep table name and POJO name same. ex. Create new Java Class i.e Person , Use hibernate plugin to create .hbm file , Give same name as Class file , Select Person as class name on next screen. This will create .hbm file with
阅读全文...
本站相关内容:

Middlegen-Hibernate和hibernate-extensions生成hbm映射文件和POJO

     摘要: 一、根据数据库表生成*.hbm.xml文件。
1、 从Hibernate官方网站下载Middlegen-Hibernate和hibernate-extensions,并解压。
2、在Middlegen-Hibernate-r5\config\database子目录中,根据我们选择的数据库类型打开对应的数据库文件。如我们这里选择MYSQL,打开mysql.xml








魏久银 2008-10-21 20:00 发表评论

hibernate:pojo


作者: 逆风逛飙  链接: http://daydaystudy.javaeye.com/blog/251673  发表时间: 2008年10月11日

声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!

pojo设计的原则:
1.有一个默认的构造方法
2.有一与业务逻辑无关的标识符
3.非final的,否则对懒加载有影响.
已有 0 人发表留言,猛击->> 这里<<-参与讨论


JavaEye推荐



Hibernate Pojo Generator: v0.9.5 released

Hibernate Pojo Generator generates all the Java code necessary to access a database via Hibernate Annotations (+ Spring) including JUnit tests (1 per table) that are able to run immediately without further customizations.

What is Hibernate? What are JPA Annotations? Why do Hibernate Mapping -hbm- files suck? The Java Persistence API and Hibernate. From The Book On Hibernate.

What is Hibernate, you ask? Well, there's a long answers to that, and there's short answers to that. The short and simple answer? Hibernate makes it easy to save data to, or load data from, a database.

Refactoring Enum --> POJO using Hibernate Persistence

Having faced this problem (mentioned in my earlier post) in the code that we inherited, I set out to refactor an Enum to a POJO. We are using Hibernate as our ORM. Here is our Enum ProcessStatus:

public enum ProcessStatus {
  RUNNING, WAITING, COMPLETE;
}

Here is the Process mapped to PROCESS table using Hibernate.

@Entity (name = "PROCESS")
public class Process {
  private ProcessStatus status;
  ...
  public void setStatus(ProcessStatus status) {
    this.status = status;
  }
  @Enumerated(value = EnumType.STRING)
  public ProcessStatus getStatus() {
    return status;
  }
  ...
}

and Let us take a client Action (called from UI layer) that uses this Enum. Assume that all the dependencies get injected when the action class is instantiated by the container (use Spring)

public class ProcessAction extends Action {
  private Process process; 
  private String status;
  private DataRepository dataRepository;
  ...
  public void setDataRepository(DataRepository dataRepository) {
    this.dataRepository = dataRepository;
  } 
  public void setStatus(String status) {
    this.status = status;
  }
  public String updateProcessStatus() {
    if (isInvalid(status)) {
      return ERROR;
    }
    process.setStatus(ProcessStatus.valueOf(status));
    dataRepository.update(process);
    return SUCCESS;
  }
  private boolean isInvalid(String status) {
    if (status == null || "".equals(status)) {
      return false;
    }
    for (ProcessStatus processStatus : ProcessStatus.values()) {
      if (processStatus.name().equalsIgnoreCase(status))
        return true;
    }
    return false;      
  }
}

Here is the DataRepository code that talks to the underlying database and issues Hibernate queries. Ideally, this should be an interface so as to facilitate unit testing with Mock objects, but for now lets take it as a concrete class)

public class DataRepository {
  private SessionFactory sessionFactory;
  ...
  private Session getSession() {
    return HibernateUtils.getSession(sessionFactory);
  }
  public void update(Object object) {
     getSession().saveOrUpdate(object);
  }
  public <T> List<T> findAll(Class<T> clazz) {
    return getSession().createCriteria(clazz).list();
  }
  ...
}

Refactoring Steps:
  1. As Enums are constants, there could be direct references to them or references to static methods that all Enums have: valueOf(String name), values() etc... References to name(), and ordinal() can as well exist in the code. Introduce a value and a name field in the Enum and the private Constructor. Give value field the same value as what ordinal() would return for that Enum constant.
    public enum ProcessStatus {
      RUNNING(0, "RUNNING"), 
      WAITING(1, "WAITING"), 
      COMPLETE(2, "COMPLETE");
    
      private String name;
      private Integer value;
    
      private ProcessStatus(Integer value, String name) {
        this.value = value;
        this.name = name;
      }
      public Integer getValue() {
        return value;
      }
      public String getName() {
        return name;
      }
    }
    

  2. Change all references in the code to the name method to getName() method and ordinal() to getValue() method. The getValue() method returns the value that ordinal() used to return earlier and the getName() method returns the name of the Enum constants.
    public class ProcessAction extends Action {
      private Process process;
      private String status;
      private DataRepository dataRepository;
      ...
      public void setDataRepository(DataRepository dataRepository) {
        this.dataRepository = dataRepository;
      } 
      public void setStatus(String status) {
        this.status = status;
      }
      public String updateProcessStatus() {
        if (isInvalid(status)) {
          return ERROR;
        }
        process.setStatus(ProcessStatus.valueOf(status));
        dataRepository.update(process);
        return SUCCESS;
      }
      private boolean isInvalid(String status) {
        if (status == null || "".equals(status)) {
          return false;
        }
        for (ProcessStatus processStatus : ProcessStatus.values()) {
          if (processStatus.          name()          getName().equalsIgnoreCase(status))
            return true;
        }
        return false;      
      }
    }
    

  3. Convert Enum to a Regular Java Class and provide implementations of values() and valueOf() etc... and the compareTo() methods. Override hashCode() and equals() methods as well.
    public class ProcessStatus implements Comparable<ProcessStatus> {
                RUNNING(0, "RUNNING"), 
                WAITING(1, "WAITING"), 
                COMPLETE(2, "COMPLETE");          
      public static final ProcessStatus RUNNING = new ProcessStatus(0, "RUNNING");
      public static final ProcessStatus WAITING = new ProcessStatus(1, "WAITING");
      public static final ProcessStatus COMPLETE = new ProcessStatus(2, "COMPLETE");
      private static ProcessStatus [] ALL = new ProcessStatus [] { RUNNING, WAITING, COMPLETE };
      
      private String name;
      private Integer value;
    
      private ProcessStatus(Integer value, String name) {
        this.value = value;
        this.name = name;
      }
      public Integer getValue() {
        return value;
      }
      public String getName() {
        return name;
      }
      public static ProcessStatus valueOf(String statusName) {
        for (ProcessStatus processStatus : ALL) {
           if (processStatus.getName().equals(statusName))
              return processStatus;
        }
        return null;
      }
      public ProcessStatus[] values() {
         return ALL;
      }
      public int compareTo(ProcessStatus other) {
        return this.value.compareTo(other.value);
      }
      public int hashCode() { ... }
      public boolean equals(Object object) { ... }
    }
    

    Run the Unit and Acceptance Tests to get a Green (assuming you are using JUnit and FIT automated testing frameworks for Unit and Acceptance tests).

  4. Next is to create a table PROCESSTATUS containing three columns id (auto-increment/sequence), name, value. Populate the table with the name and value (same as ProcessStatus constants).
    +---+----------+-------+
    |id | name     | value |
    +---+----------+-------+
    | 1 | RUNNING  | 0     |
    | 2 | WAITING  | 1     |
    | 3 | COMPLETE | 2     |
    +---+----------+-------+
    

  5. Then, map ProcessStatus class to the newly created PROCESSTATUS table. We want this class to be immutable and hence we will make the fields non-updatable and new statuses are added from the backend. Add another Id field as primary key and the corresponding getter.
              @Entity (name = "PROCESSSTATUS")
    public class ProcessStatus implements Comparable<ProcessStatus> {
      public static final ProcessStatus RUNNING = new ProcessStatus(0, "RUNNING");
      public static final ProcessStatus WAITING = new ProcessStatus(1, "WAITING");
      public static final ProcessStatus COMPLETE = new ProcessStatus(2, "COMPLETE");
      private static ProcessStatus [] ALL = new ProcessStatus [] { RUNNING, WAITING, COMPLETE };
                
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
      @Column (updatable = false, insertable = false)
      private String name;
                @Column (updatable = false, insertable = false)
      private Integer value;
    
      private ProcessStatus(Integer value, String name) {
        this.value = value;
        this.name = name;
      }          
      public Long getId() {
        return Id;
      }
      public Integer getValue() {
        return value;
      }
      public String getName() {
        return name;
      }
      public static ProcessStatus valueOf(String statusName) {
        for (ProcessStatus processStatus : ALL) {
           if (processStatus.getName().equals(statusName))
              return processStatus;
        }
        return null;
      }
      public ProcessStatus[] values() {
         return ALL;
      }
      ...
    }
    

    Update all the String references in the PROCESS table to Id references of PROCESSSTATUS table. The Process class will change as:

    @Entity (name = "PROCESS")
    public class Process {
      private ProcessStatus status;
      ...
      public void setStatus(ProcessStatus status) {
        this.status = status;
      }
                @Enumerated(value = EnumType.STRING)
                @ManyToOne
      @JoinColumn (name = "status")
      public ProcessStatus getStatus() {
        return status;
      }
      ...
    }
    

  6. Now, we need to move away from the static method references in the Client classes and get rid of values() and valueOf() methods... ProcessAction is one such class that uses these methods. We replace them with calls to methods in DataRepository class. Introduce findProcessStatusByName() method in DataRepository to replace all client calls to valueOf() method. All client calls to values() method will be replaced by findAll() method in DataRepository.
    public class DataRepository {
      private SessionFactory sessionFactory;
      ...
      private Session getSession() {
        return HibernateUtils.getSession(sessionFactory);
      }
      public void update(Object object) {
         getSession().saveOrUpdate(object);
      }
      public <T> List<T> findAll(Class<T> clazz) {
        return getSession().createCriteria(clazz).list();
      }          
      public ProcessStatus findProcessStatusByName(String name) {
        return (ProcessStatus)getSession().createCriteria(ProcessStatus.class)
                             .add(Restrictions.eq("name", name))
                             .uniqueResult();
      }
      ...
    }
    

    Here is the changed ProcessAction class

    public class ProcessAction extends Action {
      private Process process; 
      private String status;
      private DataRepository dataRepository;
      ...
      public void setDataRepository(DataRepository dataRepository) {
        this.dataRepository = dataRepository;
      } 
      public void setStatus(String status) {
        this.status = status;
      }
      public String updateProcessStatus() {
        if (isInvalid(status)) {
          return ERROR;
        }
                  ProcessStatus processStatus = ProcessStatus.valueOf(status); 
                  ProcessStatus processStatus = dataRepository.findProcessStatusByName(status);
        process.setStatus(processStatus);
        dataRepository.update(process);
        return SUCCESS;
      }
      private boolean isInvalid(String status) {
        if (status == null || "".equals(status)) {
          return false;
        }
                  for (ProcessStatus processStatus : ProcessStatus.values()) {          
        List<ProcessStatus> allStatuses = dataRepository.findAll(ProcessStatus.class);
        for (ProcessStatus processStatus : allStatuses) {
          if (processStatus.getName().equalsIgnoreCase(status))
            return true;
        }
        return false;      
      }
    }
    

    Finally, we need to remove all the references to the Enum constants, if any and replace them with calls to dataRepository.findProcessStatusByName(). Delete all the Enum constant values, values() and valuesOf() methods. We no longer need the private constructor as well. The cleaned up ProcessStatus POJO would then look like:

              @Entity (name = "PROCESSSTATUS")
    public class ProcessStatus implements Comparable<ProcessStatus> {
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
      @Column (updatable = false, insertable = false)
      private String name;
      @Column (updatable = false, insertable = false)
      private Integer value;
    
      public Long getId() {
        return Id;
      }
      public Integer getValue() {
        return value;
      }
      public String getName() {
        return name;
      }
      public int compareTo(ProcessStatus other) {
        return this.value.compareTo(other.value);
      }
      public int hashCode() { ... }
      public boolean equals(Object object) { ... }
    }
    

    Thats all, this completes this little involved refactoring.

Re-run the test suite and get the Green bar!

互联网相关内容:
Middlegen-Hibernate和hibernate-extensions生成hbm映射文件和POJO (2008年10月21日)
hibernate:pojo (2008年10月11日)
Hibernate Pojo Generator: v0.9.5 released (2008年11月07日)
What is Hibernate? What are JPA Annotations? Why do Hibernate Mapping -hbm- files suck? The Java Persistence API and Hibernate. From The Book On Hibernate. (2008年06月12日)
Refactoring Enum --> POJO using Hibernate Persistence (2007年11月01日)
hibernate 映射 pojo 过程 (2008年04月17日)
ADB and HBM (2007年10月23日)
Spring + Hibernate EJB3, POJO + JDBC? @ JAVA DEVELOPER'S JOURNAL (2007年11月02日)
Spring + Hibernate EJB3, POJO + JDBC? @ JAVA DEVELOPER'S JOURNAL (2007年11月02日)