hibernate:pojo

Sat Oct 11 20:36:50 CST 2008发表于JavaEye博客

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

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

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


JavaEye推荐



阅读全文...
 
本站相关内容:(RSS)

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.

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!

hibernate 映射 pojo 过程


网站: JavaEye  作者: commando  链接: http://commando.javaeye.com/blog/183898  发表时间: 2008年04月17日

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

我的环境是Eclipse3.3(Europa)+hibernate3+oracle10g

一. hibernate生成

    1. 生成hibernate.cfg.xml文件,修改相应的数据库连接参数。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory name="boxfmk">
        <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
        <property name="hibernate.connection.password">devgen</property>
        <property name="hibernate.connection.url">jdbc:oracle:thin:@server01:1521:orcl</property>
        <property name="hibernate.connection.username">devgen</property>
        <property name="hibernate.default_schema">DEVGEN</property>
        <property name="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</property>
    </session-factory>
</hibernate-configuration>

 

    2. open hibernate code generation dialogue中设置一下。在main标签中设置输出生成包的路径等,在exporters标签中设置所要生成的文件类型,这里选择.hbm和.java文件。如图一所示。

 

二. 相应的修改

    1. 所有的hbm文件,加入 “lazy=false”。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2008-3-19 11:03:14 by Hibernate Tools 3.2.0.b9 -->
<hibernate-mapping>
    <class name="org.wti.emergencyProcessRecord.domain.EmergencyProcessRecord" table="EMERGENCY_PROCESS_RECORD" lazy="false">

... 

    2. 类的修改

        1)    生成的类全部改成抽象类,类名前加abstract咯,文件名也加上abstract吧;

// Generated 2008-3-19 11:03:13 by Hibernate Tools 3.2.0.b9

/**
 * EmergencyProcessRecord generated by hbm2java
 */

public abstract class AbstractEmergencyProcessRecord implements java.io.Serializable {
    ...
}

 

        2)    删除类中的构造函数(这个不用多解释啦);

        3)    类中加上equals和hashcode方法。编辑界面上点击鼠标右键,弹出菜单中选择commons4E lang->generate Equals and Hashcode,在select fields中只选择id一项,如图二所示。 

@Override
	public boolean equals(final Object other) {
		if (!(other instanceof AbstractEmergencyProcessRecord))
			return false;
		AbstractEmergencyProcessRecord castOther = (AbstractEmergencyProcessRecord) other;
		return new EqualsBuilder().append(id, castOther.id).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(id).toHashCode();
	}

  

        4)    重新生成tostring方法,同上,不过这次select fields需要全部选中;

@Override
	public String toString() {
		return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("id", id).append("name", name).append(
				"startDate", startDate).append("endDate", endDate).append("place", place).append("personList",
				personList).append("accident", accident).append("processDescription", processDescription).append(
				"result", result).append("assessment", assessment).append("author", author).append("lastUpdate",
				lastUpdate).append("orgId", orgId).toString();
	}

 

        5)    在生成文件同路径下,新建类文件,名称就是hibernate所生成的java文件的名字(原来的文件已经改名字了,前面加abstract成抽象类了),生成后将鼠标光标点在类名上,按ctrl+1,在弹出的菜单中选择add generated serial version id,会产生serialVersionUID,如图三所示。

public class EmergencyProcessRecord extends AbstractEmergencyProcessRecord {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6952531987128218368L;

}

     这就完成了domain层的映射,接下来该考虑业务功能了。

 


本文的讨论也很精彩,浏览讨论>>


JavaEye推荐



Hibernate - POJO and HBM file creation best practice

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
互联网相关内容:
Hibernate Pojo Generator: v0.9.5 released (2008年11月07日)
Refactoring Enum --> POJO using Hibernate Persistence (2007年11月01日)
hibernate 映射 pojo 过程 (2008年04月17日)
Hibernate - POJO and HBM file creation best practice (2008年08月07日)
Spring + Hibernate EJB3, POJO + JDBC? @ JAVA DEVELOPER'S JOURNAL (2007年11月02日)
How to Generate Hibernate Pojo Classes from DB Tables (2007年12月01日)
BlueOxygen 'Bead' Development, from MySQL Workbench to Hibernate POJO (2008年05月18日)
How to Generate Hibernate Pojo Classes from DB Tables - wikiHow (2008年06月30日)