Java EE 5.0 实战教程 第二部分:JPA Entity编程(域建模)
域建模是每个面向对象应用程序的核心,就像人的骨骼,如果骨骼都没有,什么界面呀,数据呀都无处可靠。在JPA之前,Java EE程序需要一套域建模,还需要一套类似的Entity Bean来处理Persistence,因为Entity Bean是和EJB容器相关的,不能运用在容器之外,这样就产生了重复,而重复是程序维护的恶梦,每一个改变都需要做多处的修改,一个不小心少改了一个地方就会产生莫名其妙的错误。JPA的出现使这个问题得到解决,JPA里的Entity可以和Persistence Context剥离从而可以象普通的Java类一样使用,详见讲稿Java Persistence API。
-
Stock.java. 注意Stock.java是一个POJO,也就是最普通的Java类,通过加入@Entity注解使其变成了JPA的Entity。详见Java Persistence API教程。
package entities;
import javax.persistence.Entity; import javax.persistence.Id;
@Entity public class Stock implements java.io.Serializable {
@Id private String stockCode; private String stockName;
/** Creates a new instance of Stock */ public Stock() { }
public String getStockCode() { return stockCode; }
public void setStockCode(String stockCode) { this.stockCode = stockCode; }
public String getStockName() { return stockName; }
public void setStockName(String stockName) { this.stockName = stockName; }
}
|
-
Trade.java. 注意Trade类应用了@ManyToOne注解来确定和别的Entity的关系。详见详见Java Persistence API教程。
package entities;
import java.util.Date; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType;
@Entity() public class Trade implements java.io.Serializable {
@Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @ManyToOne private Stock stock; private long shareNum; private double price; @ManyToOne private TradeType type;
/** Creates a new instance of Trade */ public Trade() { }
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Stock getStock() { return stock; }
public void setStock(Stock stock) { this.stock = stock; }
public long getShareNum() { return shareNum; }
public void setShareNum(long shareNum) { this.shareNum = shareNum; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public TradeType getType() { return type; }
public void setType(TradeType type) { this.type = type; }
}
|
-
Holding.java.
package entities;
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne;
@Entity() public class Holding implements java.io.Serializable {
@Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id;
@OneToOne private Stock stock; private long shareNum; private double averageCost;
/** Creates a new instance of Holding */ public Holding() { }
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Stock getStock() { return stock; }
public void setStock(Stock stock) { this.stock = stock; }
public long getShareNum() { return shareNum; }
public void setShareNum(long shareNum) { this.shareNum = shareNum; }
public double getAverageCost() { return averageCost; }
public void setAverageCost(double averageCost) { this.averageCost = averageCost; }
}
|
-
TradeType.java.
package entities;
import javax.persistence.Entity; import javax.persistence.Id;
@Entity() public class TradeType implements java.io.Serializable {
@Id private int typeCode;
private String description;
public TradeType() { } public TradeType(int code) { this.typeCode = code; } public TradeType(int code, String description){ this.setTypeCode(code); this.setDescription(description); }
public static TradeType BUY = new TradeType(1, "Buy"); public static TradeType SELL = new TradeType(2, "Sell");
public int getTypeCode() { return typeCode; }
public void setTypeCode(int typeCode) { this.typeCode = typeCode; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public boolean equals(Object obj) { if(!(obj instanceof TradeType)){ return false; } TradeType theType = (TradeType) obj; if(theType.getTypeCode() == getTypeCode()){ return true; } else { return false; } }
}
|
-
读者可用拷贝的方式将这四个java类拷到NetBeans里。也可自己输入,NetBeans提供了丰富的编辑功能,象代码自动完成,实体模板及字段封装可帮助你快速地输入源代码。
-
建立持久性单元。持久性单元是JPA运行环境和物理数据库的连接,一旦指定了持久性单元,JPA运行环境就会自动地在指定的数据库里存储和提取数据。详见Java Persistence API教程。在创建持久性单元时,NetBeans还提供了一个工具,可方便地根据Entities来生成数据库表格,见c
-
-
右键“StockApp-ejb”,选“新建”-“文件/文件夹…”
-
-
-
在对话框里选“持久性”, “持久性单元”,点击“下一步”。
-
-
-
在“数据源”一项填入 jdbc/stockDS(注意大小写,和前面必须一致), 并选择“创建”,然后点击“完成”。NetBeans提供了三种表生成策略:
-
创建:在部署项目时生成和Entity对印的数据表格
-
删除并创建:部署项目时生成表格,并在取消项目部署时删除表格 ,这个选项在开发初期,数据结构改动较多时特别有用。
-
无:不进行表格生成的操作。
-
-
-
部署项目。右键“StockApp”,选择“部署项目”。
-
NetBeans自动部署项目完成后,切换到“运行环境”,展开“数据库”,连接上“…./stockDB”(用户名/密码: stock/stock, 还记得第一部分准备的数据库吗?),打开“表”目录,可看到四个表:Stock, Trade, Holding和TradeType,这是NetBeans根据之前定义的Entities自动生成的。
-
接下来需要在TRADETYPE表里加入两个常量,可通过NetBeans的数据库工具来完成。
-
右键“TRADETYPE”,选择“执行命令…”.
-
-
-
在打开的“SQL 命令1”窗口里敲入以下命令,并按执行。
-
-
insert into tradetype values(1, 'Buy');
insert into tradetype values(2, 'Sell');
-
-
在输出框里,可看见以下输出
-
-
在 0.062 秒内成功执行,但 1 行受到影响。
第 1 行,第 1 列
在 0 秒内成功执行,但 1 行受到影响。
第 3 行,第 1 列
0.062 秒后执行完毕,出现 0 个错误。
-
至此,Entity编程完毕,下面我们就可以用这些Entity来编写业务逻辑和页面了。
附录
有人会问了,你在这部分里介绍的是先编好JPA Entity然后再根据Entity生成数据库表格,如果我的项目不是新项目,只能使用已有的数据库表格,怎么办呢?别急,NetBeans提供了一个工具,可以根据数据库表格逆向生成JPA Entities。具体做法如下:
-
新建一个项目,常规或企业项目均可。
-
右键此项目,选择”新建”-“文件/文件夹…”
-
在对话框里选择“持久性” ,“通过数据库生成实体类”,然后“下一步”
-
选择你要操作的数据库连接,NetBeans会根据数据库连接提取出可用表,你可全选可用表或者是部分你感兴趣的表,然后“下一步”
-
NetBeans会根据表的名称自动给出实体类名,你可以根据需要做修改。然后指定类生成的位置和包。NetBeans还给一个机会让你创建持久性单元。最后点“完成”,NetBeans就会自动生成实体类。
-
生成的Trade.java的例子。看起来比我们自己编的还好,连NamedQuery都给做好了,注解的运用也规范多了。
…….
@Entity @Table(name = "TRADE") @NamedQueries( { @NamedQuery(name = "Trade.findById", query = "SELECT t FROM Trade t WHERE t.id = :id"), @NamedQuery(name = "Trade.findByPrice", query = "SELECT t FROM Trade t WHERE t.price = :price"), @NamedQuery(name = "Trade.findByTradingdate", query = "SELECT t FROM Trade t WHERE t.tradingdate = :tradingdate"), @NamedQuery(name = "Trade.findBySharenum", query = "SELECT t FROM Trade t WHERE t.sharenum = :sharenum") }) public class Trade implements Serializable {
@Id @Column(name = "ID", nullable = false) private BigInteger id;
@Column(name = "PRICE") private Double price;
@Column(name = "TRADINGDATE") @Temporal(TemporalType.DATE) private Date tradingdate;
@Column(name = "SHARENUM") private BigInteger sharenum;
@JoinColumn(name = "STOCK_STOCKCODE", referencedColumnName = "STOCKCODE") @ManyToOne private Stock stockStockcode;
@JoinColumn(name = "TYPE_TYPECODE", referencedColumnName = "TYPECODE") @ManyToOne private Tradetype typeTypecode;
…….
|