- 浏览: 147542 次
- 来自: ...
文章分类
最新评论
-
fisher:
真心感谢楼主! 解决了困扰我几天的大问题啊!
EntityManagerFactory -
悲剧了:
太棒了,我们项目正在用这个
struts2 convention-plugin -
nforce_com:
...
jpa继承关系详解 -
guanchuangsheng:
精辟~~
总算明白了·~
桥接模式和适配器模式的区别 -
lping2:
强,写得太全面了
EntityManagerFactory
3 Metadata
通过javax.persistence 包中定义的Annotation或者XML mapping files来指定Persistence metadata。当混合使用Annotation 和XML mapping file 的时候,如果发生冲突,那么以XML mapping file为准。
3.1 Class Metadata
3.1.1 Entity
Entity annotation用来指定entity class。它有一个属性name用来在Query中引用entity。如果不指定name,那么缺省是entity class的名字(unqualified)。
以下是个使用Entity annotation的例子:
Java代码
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
}
@Entity
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
}
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
}
@Entity
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
} 如果使用MySQL数据库,那么用MappingTool生成的SQL如下: Sql代码
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Address (id BIGINT NOT NULL, city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE OPENJPA_SEQUENCE_TABLE (ID TINYINT NOT NULL, SEQUENCE_VALUE BIGINT, PRIMARY KEY (ID)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Address (id BIGINT NOT NULL, city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE OPENJPA_SEQUENCE_TABLE (ID TINYINT NOT NULL, SEQUENCE_VALUE BIGINT, PRIMARY KEY (ID)) TYPE = innodb; JPA要求每个persistent class都必须至少声明一个identity字段,但是OpenJPA允许不声明identity字段。如果persistent class没有声明identity字段,那么OpenJPA会缺省增加id列作为数据库表的主键,同时采用Table Generator的方式为id赋值,Table Generator缺省使用OPENJPA_SEQUENCE_TABLE。
3.1.2 IdClass
当某个entity class中包含多个identity 字段的时候,必须使用identity class(例如之前提到的MagazineId类)。IdClass annotation用来指定identity class,它的value属性是java.lang.Class 型。
3.1.3 MappedSuperclass
Mapped superclass不是entity class,但是它可以为entity class定义persistent state和mapping information。Mapped superclass通常是抽象类。Mapped superclass不能用于Query,或者被运用到任何EntityManager或者Query中。Mapped superclass通过 MappedSuperclass annotation指定。
以下是个使用MappedSuperclass annotation的例子:
Java代码
@MappedSuperclass
public abstract class Document {
@Id
protected int id;
@Version
protected int version;
}
@Entity
public class Contract extends Document {
@Basic
private String name;
}
@MappedSuperclass
public abstract class Document {
@Id
protected int id;
@Version
protected int version;
}
@Entity
public class Contract extends Document {
@Basic
private String name;
} 如果使用MySQL数据库,那么用MappingTool生成的SQL如下: Sql代码
CREATE TABLE Contract (id INTEGER NOT NULL, name VARCHAR(255), version INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Contract (id INTEGER NOT NULL, name VARCHAR(255), version INTEGER, PRIMARY KEY (id)) TYPE = innodb;
3.1.4 Embeddable
Embeddable annotation指定embeddable persistent class。Embeddable instances被映射到datastore record的一部分。JPA要求Persistent class只能是entity class或embeddable class之一。OpenJPA允许Persistent class既是entity class,也是embeddable class。只要同时使用@Entity和@ Embeddable即可。
以下是个使用Embeddable annotation的例子:
Java代码
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
@Embedded
private Address address;
}
@Embeddable
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
}
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
@Embedded
private Address address;
}
@Embeddable
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
} 如果使用MySQL数据库,那么用MappingTool生成的SQL如下: Sql代码
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
从以上SQL可以看出,OpenJPA并没有为Address embeddable class生成一个表,而是在Company表中包含了Address信息。
3.1.5 EntityListeners
EntityListeners annotation用来指定entity listeners,它的value属性是java.lang.Class数组型。
3.1.6 Table
Table annotation 用来指定entity class对应的数据库表名。它有以下几个属性:
String name: 表名,缺省使用unqualified class name。
String schema: schema名。缺省使用数据库连接的缺省schema。
String catalog: catalog名. 缺省使用数据库连接的缺省catalog。
UniqueConstraint[] uniqueConstraints: Unique constraints 用来确保一个或多个列的值在表中唯一。它只有一个属性columnNames。
以下是个简单的例子:
Java代码
@Entity
@Table(name="ART", uniqueConstraints=@Unique(columnNames="TITLE"))
public class Article {
...
}
@Entity
@Table(name="ART", uniqueConstraints=@Unique(columnNames="TITLE"))
public class Article {
...
}
3.1.7 SecondaryTable
有时候一个逻辑上的记录被分散在多个数据库表中。通过SecondaryTable annotation可以指定entity class的secondary tables。通过column annotation的table属性来引用这些secondary tables。例如:
Java代码
@Entity
@Table(name="ART")
@SecondaryTable(name="ART_DATA", pkJoinColumns=@PrimaryKeyJoinColumn(name="ART_ID", referencedColumnName="ID"))
public class Article {
@Id
private long id;
@Column(table="ART_DATA")
private byte[] content;
...
}
@Entity
@Table(name="ART")
@SecondaryTable(name="ART_DATA", pkJoinColumns=@PrimaryKeyJoinColumn(name="ART_ID", referencedColumnName="ID"))
public class Article {
@Id
private long id;
@Column(table="ART_DATA")
private byte[] content;
...
}
3.2 Field and Property Metadata
JPA提供了两种访问persistent state的方法:field access和property access。每个entity只能使用field access或property access之一来访问同一个persistence state,子类和父类必须使用相同的访问方式来访问同一个persistence state。
如果使用field access,那么JPA会直接把persistent state注入到filed中,并直接从filed上得到persistent state的改变。Annotation直接标记在field上,例如:
Java代码
@ManyToOne
private Company publisher;
@ManyToOne
private Company publisher; 如果使用property access,那么JPA会通过Java Bean的"getter" 和 "setter" 方法访问persistent state。Annotation标记在"getter"方法上,例如:
Java代码
@ManyToOne
private Company getPublisher() { ... }
private void setPublisher(Company publisher) { ... }
@ManyToOne
private Company getPublisher() { ... }
private void setPublisher(Company publisher) { ... } 当使用property access 的时候,你应该只通过"getter"和"setter"方法访问persistence state。这个类中其它的方法(例如业务逻辑方法),也应该只通过"getter"和"setter"方法来访问persistence state。当你需要在"getter"和"setter"方法内添加其它业务逻辑的时候,你应该认识到,"getter"和"setter"方法也会被JPA调用。
3.2.1 Transient
Transient annotation指定一个字段为non-persistent。
3.2.2 Id
Id annotation用来指定identity字段。
3.2.3 Generated Value
GeneratedValue 用来为identity字段生成唯一值,它有两个属性,分别是strategy和generator。
Strategy有以下可选值:
GeneratorType.AUTO: 缺省值,生成策略取决于JPA的实现。
GenerationType.IDENTITY: 在插入的时候由database设置。
GenerationType.SEQUENCE: 根据数据库中序列生成。
GenerationType.TABLE: 根据数据库中某个表的某个字段的值生成。
JPA支持以下两种generator,分别是Sequence Generator和Table Generator。Sequence Generator有以下属性:
String name: 指定generator的名字。
String sequenceName: 指定数据库中序列名。
int initialValue: 指定序列的初始值。
int allocationSize: 有些数据库支持预分配一定数量的序列值,来减少访问次数以提高性能。allocationSize的缺省值是50。
Table Generator有以下属性:
String name: 指定generator的名字。
String table: 指定数据库中表名。
String pkColumnName: 指定数据库表的主键名。
String valueColumnName: 指定数据库表的保存序列值的列名。
String pkColumnValue: 指定数据库表的某个主键值。如果用同一个表来生成多个序列值,那么需要指定pkColumnValue。
int allocationSize: 每一次访问数据库的时候,预分配序列值的数目,缺省值是50。
除了identity字段之外,OpenJPA 支持在任何字段上使用 GeneratedValue annotation。 OpenJPA额外提供了两种generator,如下:
uuid-string: OpenJPA会生成128位的UUID,用16-character string表示。
uuid-hex: 跟uuid-string一样,OpenJPA会生成128位的UUID,但是用32-character hexadecimal string 表示。
以下是使用GeneratedValue的一个例子:
Java代码
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
@Entity
public class GenerationStrategy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int identity;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-string")
private String uuidString;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-hex")
private String uuidHex;
@GeneratedValue(strategy = GenerationType.TABLE, generator="tg1")
@TableGenerator(name="tg1", table="GenerationStrategyTable", pkColumnName="id", valueColumnName="sequence", allocationSize=1)
private long tableGeneratorValue;
}
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
@Entity
public class GenerationStrategy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int identity;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-string")
private String uuidString;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-hex")
private String uuidHex;
@GeneratedValue(strategy = GenerationType.TABLE, generator="tg1")
@TableGenerator(name="tg1", table="GenerationStrategyTable", pkColumnName="id", valueColumnName="sequence", allocationSize=1)
private long tableGeneratorValue;
}
以上例子中,声明了一个named generator:"tg1"。在运行时可以通过OpenJPAEntityManager. getNamedGenerator("tg1")方法来访问它。笔者通过MappingTool生成以上例子相关SQL的代码如下(也可以通过命令行生成),如果generateSql是false,那么MappingTool会直接更改数据库。
Java代码
boolean generateSql = true;
String java = "./src/com/example/jpa/GenerationStrategy.java";
if(!generateSql) {
MappingTool.main(new String[]{java});
System.out.println("the table successfully generated");
} else {
String sql = java.replace("java", "sql");
MappingTool.main(new String[]{"-sql", sql, java});
System.out.println("the sql file was successfully generated: " + sql);
}
boolean generateSql = true;
String java = "./src/com/example/jpa/GenerationStrategy.java";
if(!generateSql) {
MappingTool.main(new String[]{java});
System.out.println("the table successfully generated");
} else {
String sql = java.replace("java", "sql");
MappingTool.main(new String[]{"-sql", sql, java});
System.out.println("the sql file was successfully generated: " + sql);
}
如果使用MySql数据库,那么用MappingTool生成的SQL如下:Sql代码
CREATE TABLE GenerationStrategy (identity INTEGER NOT NULL AUTO_INCREMENT, tableGeneratorValue BIGINT, uuidHex VARCHAR(255), uuidString VARCHAR(255), PRIMARY KEY (identity)) TYPE = innodb;
CREATE TABLE GenerationStrategyTable (ID VARCHAR(255) NOT NULL, SEQUENCE BIGINT, PRIMARY KEY (ID)) TYPE = innodb;
CREATE TABLE GenerationStrategy (identity INTEGER NOT NULL AUTO_INCREMENT, tableGeneratorValue BIGINT, uuidHex VARCHAR(255), uuidString VARCHAR(255), PRIMARY KEY (identity)) TYPE = innodb;
CREATE TABLE GenerationStrategyTable (ID VARCHAR(255) NOT NULL, SEQUENCE BIGINT, PRIMARY KEY (ID)) TYPE = innodb;
3.2.4 Embedded Id
如果一个entity class有多个identity字段,那么你可以声明多个@Id 字段,或者声明一个@EmbeddedId字段。@EmbeddedId字段必须是一个embeddable entity class。
3.2.5 Version
Version annotation用来指定version字段。
3.2.6 Basic
跟Transient annotation不同,basic annotation指定一个字段为persistent。可以在以下类型的字段上使用basic annotation:primitives, primitive wrappers, java.lang.String, byte[], Byte[], char[], Character[], java.math.BigDecimal, java.math.BigInteger, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Timestamp, Enums, 和 Serializable types.
Basic annotation有以下两个属性:
FetchType fetch: 指定加载方式,可选值FetchType.EAGER(缺省值)和 FetchType.LAZY。
boolean optional: datastore 中相关字段是否允许为null,缺省值是true。
OpenJPA 可以在任何字段上进行延迟加载(lazy-load),也允许在运行时动态修改某个字段的加载方式。
3.2.7 Embedded
@Embedded字段必须是字段必须是一个embeddable entity class,它用来映射datastore record的一部分。
3.2.8 Many To One
如果多个entity A引用entity B,而且其它entity A也可能引用相同的entity B,那么称A和B之间的关系是Many To One。JPA使用ManyToOne annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。
CascadeType[] cascade: 指定级连行为,缺省是空数组。
FetchType fetch: 指定加载方式,可选值FetchType.EAGER(缺省值)和 FetchType.LAZY。
boolean optional: 关联的entity是否必须存在。如果是false,那么这个字段不能是null,缺省值是true。
关于Cascade Type,有以下可选值:CascadeType.PERSIST、CascadeType.REMOVE、CascadeType.REFRESH和CascadeType.MERGE。CascadeType.ALL用来指定以上所有CascadeType,以下两种写法是等价的:
Java代码
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.REFRESH,CascadeType.MERGE})
private Company publisher;
@ManyToOne(cascade=CascadeType.ALL)
private Company publisher;
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.REFRESH,CascadeType.MERGE})
private Company publisher;
@ManyToOne(cascade=CascadeType.ALL)
private Company publisher;
以下是个使用ManyToOne annotation的例子:
Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
private Publisher publisher;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
如果不希望使用OpenJPA缺省的关联字段名(例如publisher_publisherId),那么可以使用JoinColumn annotation,例如: Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
@JoinColumn(name = "publisherId", referencedColumnName = "publisherId")
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
@JoinColumn(name = "publisherId", referencedColumnName = "publisherId")
private Publisher publisher;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisherId);
3.2.9 One To Many
如果entity A引用多个entity B,而且没有两个entity A引用相同的entity B,那么称A和B之间的关系是One To Many。JPA使用OneToMany annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。通常使用在parameterized 集合类上,如果集合类不是parameterized 类型,那么必须指定这个属性。
String mappedBy: 用来之指定双向关系另一端的entity name。如果没有指定这个属性,那么认为是标准的单向关系。
CascadeType[] cascade: A指定级连行为,缺省是空数组。
FetchType fetch: 指定load方式,可选值FetchType.EAGER和 FetchType.LAZY(缺省值)。
如果使用OneToMany关系,那么缺省情况下JPA将会生成中间表来进行关联,例如:
Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE Publisher_Magazine (Publisher_publisherId INTEGER, magazines_magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON Publisher_Magazine (magazines_magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHER_PUBLISHERID ON Publisher_Magazine (Publisher_publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE Publisher_Magazine (Publisher_publisherId INTEGER, magazines_magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON Publisher_Magazine (magazines_magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHER_PUBLISHERID ON Publisher_Magazine (Publisher_publisherId); 如果不希望使用OpenJPA缺省的关联表名和字段名(例如Publisher_Magazine,Publisher_publisherId),那么可以使用JoinTable annotation,例如: Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
@JoinTable(name="PublisherMagazine",
joinColumns=@JoinColumn(name="publisherId", referencedColumnName="publisherId"),
inverseJoinColumns=@JoinColumn(name="magazineId", referencedColumnName="magazineId"))
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
@JoinTable(name="PublisherMagazine",
joinColumns=@JoinColumn(name="publisherId", referencedColumnName="publisherId"),
inverseJoinColumns=@JoinColumn(name="magazineId", referencedColumnName="magazineId"))
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE PublisherMagazine (publisherId INTEGER, magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON PublisherMagazine (magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHERID ON PublisherMagazine (publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE PublisherMagazine (publisherId INTEGER, magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON PublisherMagazine (magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHERID ON PublisherMagazine (publisherId);
考虑下面这种情况:
Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany()
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany()
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
} 在这种情况下,JPA会根据Publisher上的OneToMany关系生成关联表,同时根据Magazine上的ManyToOne关系在Magazine表上生成关联字段。如果希望避免这种冗余,那么可以通过OneToMany上的mappedBy属性来告知JPA:谁拥有这个双向关系。 例如: Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany(mappedBy="publisher")
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany(mappedBy="publisher")
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
3.2.10 One To One
如果entity A引用唯一的entity B,而且没有其它entity A引用相同的entity B,那么称A和B之间的关系是One To One。JPA使用OneToOne annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。通常也可以从字段类型上得到这个信息。
String mappedBy: 用来之指定双向关系另一端的entity name。如果没有指定这个属性,那么认为是标准的单向关系。
CascadeType[] cascade: A指定级连行为,缺省是空数组。
FetchType fetch: 指定load方式,可选值FetchType.EAGER(缺省值)和 FetchType.LAZY。
boolean optional: 关联的entity是否必须存在。如果是false,那么这个字段不能是null,缺省值是true。
以下是几个使用OneToOne关系的例子:
Java代码
@Entity
public class Company {
@Id
private int id;
@OneToOne
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne
private Company company;
}
@Entity
public class Company {
@Id
private int id;
@OneToOne
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne
private Company company;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下(两个表都生成了跟对方表主键类型相同的字段及其索引,但是并没有显式的外键关联): Sql代码
CREATE TABLE Address (id INTEGER NOT NULL, company_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_ADDRESS_COMPANY ON Address (company_id);
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
CREATE TABLE Address (id INTEGER NOT NULL, company_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_ADDRESS_COMPANY ON Address (company_id);
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
如果将Address类中company属性的annotation改成@OneToOne(mappedBy = "address"),那么用MappingTool生成的SQL(MySQL数据库)如下(只有Company表生成了跟Address表主键类型相同的字段及其索引,但是并没有显式的外键关联):
Sql代码
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
如果不希望使用OpenJPA缺省的关联字段名(例如address_id),那么可以使用JoinColumn annotation,例如:
Java代码
@Entity
public class Company {
@Id
private int id;
@OneToOne
@JoinColumn(name = "AddressId", referencedColumnName = "id")
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne(mappedBy = "address")
private Company company;
}
@Entity
public class Company {
@Id
private int id;
@OneToOne
@JoinColumn(name = "AddressId", referencedColumnName = "id")
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne(mappedBy = "address")
private Company company;
}
用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, AddressId INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (AddressId);
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, AddressId INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (AddressId);
3.2.11 Many To Many
如果entity A引用多个entity B,而且其它的entity A也可能引用其中某些entity B,那么称A和B之间的关系是Many To Many。JPA使用ManyToMany annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。通常使用在parameterized 集合类上,如果集合类不是parameterized 类型,那么必须指定这个属性。
String mappedBy: 用来之指定双向关系另一端的entity name。如果没有指定这个属性,那么认为是标准的单向关系。
CascadeType[] cascade: A指定级连行为,缺省是空数组。
FetchType fetch: 指定load方式,可选值FetchType.EAGER和 FetchType.LAZY(缺省值)。
如果使用ManyToMany关系,那么JPA将会生成中间表来进行关联,例如:
Java代码
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Author> authors;
}
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Author> authors;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Article_Author (Article_articleId INTEGER, authors_authorId INTEGER) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (Author_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_RTCLTHR_ARTICLE_ARTICLEID ON Article_Author (Article_articleId);
CREATE INDEX I_RTCLTHR_ELEMENT ON Article_Author (authors_authorId);
CREATE INDEX I_THR_TCL_AUTHOR_AUTHORID ON Author_Article (Author_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Article_Author (Article_articleId INTEGER, authors_authorId INTEGER) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (Author_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_RTCLTHR_ARTICLE_ARTICLEID ON Article_Author (Article_articleId);
CREATE INDEX I_RTCLTHR_ELEMENT ON Article_Author (authors_authorId);
CREATE INDEX I_THR_TCL_AUTHOR_AUTHORID ON Author_Article (Author_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
如果将Article类中authors属性的annotation改成@ManyToMany(cascade=CascadeType.ALL, mappedBy="articles"),那么用MappingTool生成的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (authors_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_THR_TCL_AUTHORS_AUTHORID ON Author_Article (authors_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (authors_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_THR_TCL_AUTHORS_AUTHORID ON Author_Article (authors_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
如果不希望使用OpenJPA缺省的关联表名和字段名(例如Author_Article,authors_authorId),那么可以使用JoinTable annotation,例如:
Java代码
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="AuthorArticle",
joinColumns=@JoinColumn(name="AuthorId", referencedColumnName="AuthorId"),
inverseJoinColumns=@JoinColumn(name="ArticleId", referencedColumnName="ArticleId"))
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL, mappedBy="articles")
private List<Author> authors;
}
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="AuthorArticle",
joinColumns=@JoinColumn(name="AuthorId", referencedColumnName="AuthorId"),
inverseJoinColumns=@JoinColumn(name="ArticleId", referencedColumnName="ArticleId"))
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL, mappedBy="articles")
private List<Author> authors;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE AuthorArticle (AuthorId INTEGER, ArticleId INTEGER) TYPE = innodb;
CREATE INDEX I_THRRTCL_AUTHORID ON AuthorArticle (AuthorId);
CREATE INDEX I_THRRTCL_ELEMENT ON AuthorArticle (ArticleId);
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE AuthorArticle (AuthorId INTEGER, ArticleId INTEGER) TYPE = innodb;
CREATE INDEX I_THRRTCL_AUTHORID ON AuthorArticle (AuthorId);
CREATE INDEX I_THRRTCL_ELEMENT ON AuthorArticle (ArticleId);
3.2.12 Order By
由于关系型数据库并不保存records的顺序,因此为了保证集合类型的字段有一致的顺序,必须使用OrderBy annotation。缺省是采用identity values的升序。以下是个简单的例子:
Java代码
@OrderBy("lastName, firstName")
private Collection<Author> authors;
@OrderBy("lastName, firstName")
private Collection<Author> authors;
3.2.13 Map Key
JPA在OneToMany或者ManyToMany关系中支持Map类型的字段,关联的entities组成了Map的value。JPA在每个entity中挑选一个字段作为Map的key。MapKey annotation有一个name属性,用来指定被挑选作为key的字段名。如果没有指定name,那么会使用关联entity的identity字段。
3.2.14 Persistent Field Defaults
当某个字段没有使用以上介绍的annotations时,JPA对该字段采取以下的缺省行为:
被声明成static, transient, final的字段缺省是non-persistent。
以下类型的字段:primitive type, primitive wrapper type, java.lang.String, byte[], Byte[], char[], Character[], java.math.BigDecimal, java.math.BigInteger, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Timestamp, Serializable type 缺省时persistent,就像使用了Basic annotation一样。
Embeddable type缺省是persistent,就像使用了Embedded annotation一样。
以上以外的字段缺省是non-persistent。
3.2.15 Column
Column annotation 用来指定列的属性,它有以下可选属性:
String name: 列名,缺省是属性名。
String columnDefinition: 数据库中列的数据类型。只有当JPA vendor支持通过metadata创建表的时候,这个属性才被使用。
int length: 列的长度,这个属性通常也是在创建表的时候使用。也有的JPA vendor在flush之前通过这个属性验证数据。
int precision: 列的精度。
int scale: 列的小数范围。
boolean nullable: 列是否允许为null。缺省是true。
boolean insertable: 如果false,那么SQL 的insert语句中会忽略这个列。缺省是true。
boolean updatable: 如果false,那么SQL 的update语句中会忽略这个列。缺省是true。
String table: 指定secondary table的表名。
通过javax.persistence 包中定义的Annotation或者XML mapping files来指定Persistence metadata。当混合使用Annotation 和XML mapping file 的时候,如果发生冲突,那么以XML mapping file为准。
3.1 Class Metadata
3.1.1 Entity
Entity annotation用来指定entity class。它有一个属性name用来在Query中引用entity。如果不指定name,那么缺省是entity class的名字(unqualified)。
以下是个使用Entity annotation的例子:
Java代码
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
}
@Entity
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
}
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
}
@Entity
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
} 如果使用MySQL数据库,那么用MappingTool生成的SQL如下: Sql代码
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Address (id BIGINT NOT NULL, city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE OPENJPA_SEQUENCE_TABLE (ID TINYINT NOT NULL, SEQUENCE_VALUE BIGINT, PRIMARY KEY (ID)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Address (id BIGINT NOT NULL, city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE OPENJPA_SEQUENCE_TABLE (ID TINYINT NOT NULL, SEQUENCE_VALUE BIGINT, PRIMARY KEY (ID)) TYPE = innodb; JPA要求每个persistent class都必须至少声明一个identity字段,但是OpenJPA允许不声明identity字段。如果persistent class没有声明identity字段,那么OpenJPA会缺省增加id列作为数据库表的主键,同时采用Table Generator的方式为id赋值,Table Generator缺省使用OPENJPA_SEQUENCE_TABLE。
3.1.2 IdClass
当某个entity class中包含多个identity 字段的时候,必须使用identity class(例如之前提到的MagazineId类)。IdClass annotation用来指定identity class,它的value属性是java.lang.Class 型。
3.1.3 MappedSuperclass
Mapped superclass不是entity class,但是它可以为entity class定义persistent state和mapping information。Mapped superclass通常是抽象类。Mapped superclass不能用于Query,或者被运用到任何EntityManager或者Query中。Mapped superclass通过 MappedSuperclass annotation指定。
以下是个使用MappedSuperclass annotation的例子:
Java代码
@MappedSuperclass
public abstract class Document {
@Id
protected int id;
@Version
protected int version;
}
@Entity
public class Contract extends Document {
@Basic
private String name;
}
@MappedSuperclass
public abstract class Document {
@Id
protected int id;
@Version
protected int version;
}
@Entity
public class Contract extends Document {
@Basic
private String name;
} 如果使用MySQL数据库,那么用MappingTool生成的SQL如下: Sql代码
CREATE TABLE Contract (id INTEGER NOT NULL, name VARCHAR(255), version INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Contract (id INTEGER NOT NULL, name VARCHAR(255), version INTEGER, PRIMARY KEY (id)) TYPE = innodb;
3.1.4 Embeddable
Embeddable annotation指定embeddable persistent class。Embeddable instances被映射到datastore record的一部分。JPA要求Persistent class只能是entity class或embeddable class之一。OpenJPA允许Persistent class既是entity class,也是embeddable class。只要同时使用@Entity和@ Embeddable即可。
以下是个使用Embeddable annotation的例子:
Java代码
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
@Embedded
private Address address;
}
@Embeddable
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
}
@Entity
public class Company {
@Id
private int id;
@Basic
private String name;
@Embedded
private Address address;
}
@Embeddable
public class Address {
@Basic
private String province;
@Basic
private String city;
@Basic
private String street;
@Basic
private String zip;
} 如果使用MySQL数据库,那么用MappingTool生成的SQL如下: Sql代码
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, name VARCHAR(255), city VARCHAR(255), province VARCHAR(255), street VARCHAR(255), zip VARCHAR(255), PRIMARY KEY (id)) TYPE = innodb;
从以上SQL可以看出,OpenJPA并没有为Address embeddable class生成一个表,而是在Company表中包含了Address信息。
3.1.5 EntityListeners
EntityListeners annotation用来指定entity listeners,它的value属性是java.lang.Class数组型。
3.1.6 Table
Table annotation 用来指定entity class对应的数据库表名。它有以下几个属性:
String name: 表名,缺省使用unqualified class name。
String schema: schema名。缺省使用数据库连接的缺省schema。
String catalog: catalog名. 缺省使用数据库连接的缺省catalog。
UniqueConstraint[] uniqueConstraints: Unique constraints 用来确保一个或多个列的值在表中唯一。它只有一个属性columnNames。
以下是个简单的例子:
Java代码
@Entity
@Table(name="ART", uniqueConstraints=@Unique(columnNames="TITLE"))
public class Article {
...
}
@Entity
@Table(name="ART", uniqueConstraints=@Unique(columnNames="TITLE"))
public class Article {
...
}
3.1.7 SecondaryTable
有时候一个逻辑上的记录被分散在多个数据库表中。通过SecondaryTable annotation可以指定entity class的secondary tables。通过column annotation的table属性来引用这些secondary tables。例如:
Java代码
@Entity
@Table(name="ART")
@SecondaryTable(name="ART_DATA", pkJoinColumns=@PrimaryKeyJoinColumn(name="ART_ID", referencedColumnName="ID"))
public class Article {
@Id
private long id;
@Column(table="ART_DATA")
private byte[] content;
...
}
@Entity
@Table(name="ART")
@SecondaryTable(name="ART_DATA", pkJoinColumns=@PrimaryKeyJoinColumn(name="ART_ID", referencedColumnName="ID"))
public class Article {
@Id
private long id;
@Column(table="ART_DATA")
private byte[] content;
...
}
3.2 Field and Property Metadata
JPA提供了两种访问persistent state的方法:field access和property access。每个entity只能使用field access或property access之一来访问同一个persistence state,子类和父类必须使用相同的访问方式来访问同一个persistence state。
如果使用field access,那么JPA会直接把persistent state注入到filed中,并直接从filed上得到persistent state的改变。Annotation直接标记在field上,例如:
Java代码
@ManyToOne
private Company publisher;
@ManyToOne
private Company publisher; 如果使用property access,那么JPA会通过Java Bean的"getter" 和 "setter" 方法访问persistent state。Annotation标记在"getter"方法上,例如:
Java代码
@ManyToOne
private Company getPublisher() { ... }
private void setPublisher(Company publisher) { ... }
@ManyToOne
private Company getPublisher() { ... }
private void setPublisher(Company publisher) { ... } 当使用property access 的时候,你应该只通过"getter"和"setter"方法访问persistence state。这个类中其它的方法(例如业务逻辑方法),也应该只通过"getter"和"setter"方法来访问persistence state。当你需要在"getter"和"setter"方法内添加其它业务逻辑的时候,你应该认识到,"getter"和"setter"方法也会被JPA调用。
3.2.1 Transient
Transient annotation指定一个字段为non-persistent。
3.2.2 Id
Id annotation用来指定identity字段。
3.2.3 Generated Value
GeneratedValue 用来为identity字段生成唯一值,它有两个属性,分别是strategy和generator。
Strategy有以下可选值:
GeneratorType.AUTO: 缺省值,生成策略取决于JPA的实现。
GenerationType.IDENTITY: 在插入的时候由database设置。
GenerationType.SEQUENCE: 根据数据库中序列生成。
GenerationType.TABLE: 根据数据库中某个表的某个字段的值生成。
JPA支持以下两种generator,分别是Sequence Generator和Table Generator。Sequence Generator有以下属性:
String name: 指定generator的名字。
String sequenceName: 指定数据库中序列名。
int initialValue: 指定序列的初始值。
int allocationSize: 有些数据库支持预分配一定数量的序列值,来减少访问次数以提高性能。allocationSize的缺省值是50。
Table Generator有以下属性:
String name: 指定generator的名字。
String table: 指定数据库中表名。
String pkColumnName: 指定数据库表的主键名。
String valueColumnName: 指定数据库表的保存序列值的列名。
String pkColumnValue: 指定数据库表的某个主键值。如果用同一个表来生成多个序列值,那么需要指定pkColumnValue。
int allocationSize: 每一次访问数据库的时候,预分配序列值的数目,缺省值是50。
除了identity字段之外,OpenJPA 支持在任何字段上使用 GeneratedValue annotation。 OpenJPA额外提供了两种generator,如下:
uuid-string: OpenJPA会生成128位的UUID,用16-character string表示。
uuid-hex: 跟uuid-string一样,OpenJPA会生成128位的UUID,但是用32-character hexadecimal string 表示。
以下是使用GeneratedValue的一个例子:
Java代码
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
@Entity
public class GenerationStrategy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int identity;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-string")
private String uuidString;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-hex")
private String uuidHex;
@GeneratedValue(strategy = GenerationType.TABLE, generator="tg1")
@TableGenerator(name="tg1", table="GenerationStrategyTable", pkColumnName="id", valueColumnName="sequence", allocationSize=1)
private long tableGeneratorValue;
}
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
@Entity
public class GenerationStrategy {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int identity;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-string")
private String uuidString;
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-hex")
private String uuidHex;
@GeneratedValue(strategy = GenerationType.TABLE, generator="tg1")
@TableGenerator(name="tg1", table="GenerationStrategyTable", pkColumnName="id", valueColumnName="sequence", allocationSize=1)
private long tableGeneratorValue;
}
以上例子中,声明了一个named generator:"tg1"。在运行时可以通过OpenJPAEntityManager. getNamedGenerator("tg1")方法来访问它。笔者通过MappingTool生成以上例子相关SQL的代码如下(也可以通过命令行生成),如果generateSql是false,那么MappingTool会直接更改数据库。
Java代码
boolean generateSql = true;
String java = "./src/com/example/jpa/GenerationStrategy.java";
if(!generateSql) {
MappingTool.main(new String[]{java});
System.out.println("the table successfully generated");
} else {
String sql = java.replace("java", "sql");
MappingTool.main(new String[]{"-sql", sql, java});
System.out.println("the sql file was successfully generated: " + sql);
}
boolean generateSql = true;
String java = "./src/com/example/jpa/GenerationStrategy.java";
if(!generateSql) {
MappingTool.main(new String[]{java});
System.out.println("the table successfully generated");
} else {
String sql = java.replace("java", "sql");
MappingTool.main(new String[]{"-sql", sql, java});
System.out.println("the sql file was successfully generated: " + sql);
}
如果使用MySql数据库,那么用MappingTool生成的SQL如下:Sql代码
CREATE TABLE GenerationStrategy (identity INTEGER NOT NULL AUTO_INCREMENT, tableGeneratorValue BIGINT, uuidHex VARCHAR(255), uuidString VARCHAR(255), PRIMARY KEY (identity)) TYPE = innodb;
CREATE TABLE GenerationStrategyTable (ID VARCHAR(255) NOT NULL, SEQUENCE BIGINT, PRIMARY KEY (ID)) TYPE = innodb;
CREATE TABLE GenerationStrategy (identity INTEGER NOT NULL AUTO_INCREMENT, tableGeneratorValue BIGINT, uuidHex VARCHAR(255), uuidString VARCHAR(255), PRIMARY KEY (identity)) TYPE = innodb;
CREATE TABLE GenerationStrategyTable (ID VARCHAR(255) NOT NULL, SEQUENCE BIGINT, PRIMARY KEY (ID)) TYPE = innodb;
3.2.4 Embedded Id
如果一个entity class有多个identity字段,那么你可以声明多个@Id 字段,或者声明一个@EmbeddedId字段。@EmbeddedId字段必须是一个embeddable entity class。
3.2.5 Version
Version annotation用来指定version字段。
3.2.6 Basic
跟Transient annotation不同,basic annotation指定一个字段为persistent。可以在以下类型的字段上使用basic annotation:primitives, primitive wrappers, java.lang.String, byte[], Byte[], char[], Character[], java.math.BigDecimal, java.math.BigInteger, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Timestamp, Enums, 和 Serializable types.
Basic annotation有以下两个属性:
FetchType fetch: 指定加载方式,可选值FetchType.EAGER(缺省值)和 FetchType.LAZY。
boolean optional: datastore 中相关字段是否允许为null,缺省值是true。
OpenJPA 可以在任何字段上进行延迟加载(lazy-load),也允许在运行时动态修改某个字段的加载方式。
3.2.7 Embedded
@Embedded字段必须是字段必须是一个embeddable entity class,它用来映射datastore record的一部分。
3.2.8 Many To One
如果多个entity A引用entity B,而且其它entity A也可能引用相同的entity B,那么称A和B之间的关系是Many To One。JPA使用ManyToOne annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。
CascadeType[] cascade: 指定级连行为,缺省是空数组。
FetchType fetch: 指定加载方式,可选值FetchType.EAGER(缺省值)和 FetchType.LAZY。
boolean optional: 关联的entity是否必须存在。如果是false,那么这个字段不能是null,缺省值是true。
关于Cascade Type,有以下可选值:CascadeType.PERSIST、CascadeType.REMOVE、CascadeType.REFRESH和CascadeType.MERGE。CascadeType.ALL用来指定以上所有CascadeType,以下两种写法是等价的:
Java代码
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.REFRESH,CascadeType.MERGE})
private Company publisher;
@ManyToOne(cascade=CascadeType.ALL)
private Company publisher;
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE, CascadeType.REFRESH,CascadeType.MERGE})
private Company publisher;
@ManyToOne(cascade=CascadeType.ALL)
private Company publisher;
以下是个使用ManyToOne annotation的例子:
Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
private Publisher publisher;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
如果不希望使用OpenJPA缺省的关联字段名(例如publisher_publisherId),那么可以使用JoinColumn annotation,例如: Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
@JoinColumn(name = "publisherId", referencedColumnName = "publisherId")
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne
@JoinColumn(name = "publisherId", referencedColumnName = "publisherId")
private Publisher publisher;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisherId);
3.2.9 One To Many
如果entity A引用多个entity B,而且没有两个entity A引用相同的entity B,那么称A和B之间的关系是One To Many。JPA使用OneToMany annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。通常使用在parameterized 集合类上,如果集合类不是parameterized 类型,那么必须指定这个属性。
String mappedBy: 用来之指定双向关系另一端的entity name。如果没有指定这个属性,那么认为是标准的单向关系。
CascadeType[] cascade: A指定级连行为,缺省是空数组。
FetchType fetch: 指定load方式,可选值FetchType.EAGER和 FetchType.LAZY(缺省值)。
如果使用OneToMany关系,那么缺省情况下JPA将会生成中间表来进行关联,例如:
Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE Publisher_Magazine (Publisher_publisherId INTEGER, magazines_magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON Publisher_Magazine (magazines_magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHER_PUBLISHERID ON Publisher_Magazine (Publisher_publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE Publisher_Magazine (Publisher_publisherId INTEGER, magazines_magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON Publisher_Magazine (magazines_magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHER_PUBLISHERID ON Publisher_Magazine (Publisher_publisherId); 如果不希望使用OpenJPA缺省的关联表名和字段名(例如Publisher_Magazine,Publisher_publisherId),那么可以使用JoinTable annotation,例如: Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
@JoinTable(name="PublisherMagazine",
joinColumns=@JoinColumn(name="publisherId", referencedColumnName="publisherId"),
inverseJoinColumns=@JoinColumn(name="magazineId", referencedColumnName="magazineId"))
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany
@JoinTable(name="PublisherMagazine",
joinColumns=@JoinColumn(name="publisherId", referencedColumnName="publisherId"),
inverseJoinColumns=@JoinColumn(name="magazineId", referencedColumnName="magazineId"))
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE PublisherMagazine (publisherId INTEGER, magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON PublisherMagazine (magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHERID ON PublisherMagazine (publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE TABLE PublisherMagazine (publisherId INTEGER, magazineId INTEGER) TYPE = innodb;
CREATE INDEX I_PBLSGZN_ELEMENT ON PublisherMagazine (magazineId);
CREATE INDEX I_PBLSGZN_PUBLISHERID ON PublisherMagazine (publisherId);
考虑下面这种情况:
Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany()
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany()
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
} 在这种情况下,JPA会根据Publisher上的OneToMany关系生成关联表,同时根据Magazine上的ManyToOne关系在Magazine表上生成关联字段。如果希望避免这种冗余,那么可以通过OneToMany上的mappedBy属性来告知JPA:谁拥有这个双向关系。 例如: Java代码
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany(mappedBy="publisher")
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
}
@Entity
public class Publisher {
@Id
private int publisherId;
@OneToMany(mappedBy="publisher")
private List<Magazine> magazines;
}
@Entity
public class Magazine {
@Id
private int magazineId;
@ManyToOne()
private Publisher publisher;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
CREATE TABLE Magazine (magazineId INTEGER NOT NULL, publisher_publisherId INTEGER, PRIMARY KEY (magazineId)) TYPE = innodb;
CREATE TABLE Publisher (publisherId INTEGER NOT NULL, PRIMARY KEY (publisherId)) TYPE = innodb;
CREATE INDEX I_MGAZINE_PUBLISHER ON Magazine (publisher_publisherId);
3.2.10 One To One
如果entity A引用唯一的entity B,而且没有其它entity A引用相同的entity B,那么称A和B之间的关系是One To One。JPA使用OneToOne annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。通常也可以从字段类型上得到这个信息。
String mappedBy: 用来之指定双向关系另一端的entity name。如果没有指定这个属性,那么认为是标准的单向关系。
CascadeType[] cascade: A指定级连行为,缺省是空数组。
FetchType fetch: 指定load方式,可选值FetchType.EAGER(缺省值)和 FetchType.LAZY。
boolean optional: 关联的entity是否必须存在。如果是false,那么这个字段不能是null,缺省值是true。
以下是几个使用OneToOne关系的例子:
Java代码
@Entity
public class Company {
@Id
private int id;
@OneToOne
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne
private Company company;
}
@Entity
public class Company {
@Id
private int id;
@OneToOne
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne
private Company company;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下(两个表都生成了跟对方表主键类型相同的字段及其索引,但是并没有显式的外键关联): Sql代码
CREATE TABLE Address (id INTEGER NOT NULL, company_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_ADDRESS_COMPANY ON Address (company_id);
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
CREATE TABLE Address (id INTEGER NOT NULL, company_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_ADDRESS_COMPANY ON Address (company_id);
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
如果将Address类中company属性的annotation改成@OneToOne(mappedBy = "address"),那么用MappingTool生成的SQL(MySQL数据库)如下(只有Company表生成了跟Address表主键类型相同的字段及其索引,但是并没有显式的外键关联):
Sql代码
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, address_id INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (address_id);
如果不希望使用OpenJPA缺省的关联字段名(例如address_id),那么可以使用JoinColumn annotation,例如:
Java代码
@Entity
public class Company {
@Id
private int id;
@OneToOne
@JoinColumn(name = "AddressId", referencedColumnName = "id")
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne(mappedBy = "address")
private Company company;
}
@Entity
public class Company {
@Id
private int id;
@OneToOne
@JoinColumn(name = "AddressId", referencedColumnName = "id")
private Address address;
}
@Entity
public class Address {
@Id
private int id;
@OneToOne(mappedBy = "address")
private Company company;
}
用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, AddressId INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (AddressId);
CREATE TABLE Address (id INTEGER NOT NULL, PRIMARY KEY (id)) TYPE = innodb;
CREATE TABLE Company (id INTEGER NOT NULL, AddressId INTEGER, PRIMARY KEY (id)) TYPE = innodb;
CREATE INDEX I_COMPANY_ADDRESS ON Company (AddressId);
3.2.11 Many To Many
如果entity A引用多个entity B,而且其它的entity A也可能引用其中某些entity B,那么称A和B之间的关系是Many To Many。JPA使用ManyToMany annotation来指定这种关系。它有以下属性:
Class targetEntity: 关联entity的Class。通常使用在parameterized 集合类上,如果集合类不是parameterized 类型,那么必须指定这个属性。
String mappedBy: 用来之指定双向关系另一端的entity name。如果没有指定这个属性,那么认为是标准的单向关系。
CascadeType[] cascade: A指定级连行为,缺省是空数组。
FetchType fetch: 指定load方式,可选值FetchType.EAGER和 FetchType.LAZY(缺省值)。
如果使用ManyToMany关系,那么JPA将会生成中间表来进行关联,例如:
Java代码
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Author> authors;
}
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL)
private List<Author> authors;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Article_Author (Article_articleId INTEGER, authors_authorId INTEGER) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (Author_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_RTCLTHR_ARTICLE_ARTICLEID ON Article_Author (Article_articleId);
CREATE INDEX I_RTCLTHR_ELEMENT ON Article_Author (authors_authorId);
CREATE INDEX I_THR_TCL_AUTHOR_AUTHORID ON Author_Article (Author_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Article_Author (Article_articleId INTEGER, authors_authorId INTEGER) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (Author_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_RTCLTHR_ARTICLE_ARTICLEID ON Article_Author (Article_articleId);
CREATE INDEX I_RTCLTHR_ELEMENT ON Article_Author (authors_authorId);
CREATE INDEX I_THR_TCL_AUTHOR_AUTHORID ON Author_Article (Author_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
如果将Article类中authors属性的annotation改成@ManyToMany(cascade=CascadeType.ALL, mappedBy="articles"),那么用MappingTool生成的SQL(MySQL数据库)如下:
Sql代码
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (authors_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_THR_TCL_AUTHORS_AUTHORID ON Author_Article (authors_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE Author_Article (authors_authorId INTEGER, articles_articleId INTEGER) TYPE = innodb;
CREATE INDEX I_THR_TCL_AUTHORS_AUTHORID ON Author_Article (authors_authorId);
CREATE INDEX I_THR_TCL_ELEMENT ON Author_Article (articles_articleId);
如果不希望使用OpenJPA缺省的关联表名和字段名(例如Author_Article,authors_authorId),那么可以使用JoinTable annotation,例如:
Java代码
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="AuthorArticle",
joinColumns=@JoinColumn(name="AuthorId", referencedColumnName="AuthorId"),
inverseJoinColumns=@JoinColumn(name="ArticleId", referencedColumnName="ArticleId"))
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL, mappedBy="articles")
private List<Author> authors;
}
@Entity
public class Author {
@Id
private int authorId;
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="AuthorArticle",
joinColumns=@JoinColumn(name="AuthorId", referencedColumnName="AuthorId"),
inverseJoinColumns=@JoinColumn(name="ArticleId", referencedColumnName="ArticleId"))
private List<Article> articles;
}
@Entity
public class Article {
@Id
private int articleId;
@ManyToMany(cascade=CascadeType.ALL, mappedBy="articles")
private List<Author> authors;
} 用MappingTool生成以上两个entity class的SQL(MySQL数据库)如下: Sql代码
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE AuthorArticle (AuthorId INTEGER, ArticleId INTEGER) TYPE = innodb;
CREATE INDEX I_THRRTCL_AUTHORID ON AuthorArticle (AuthorId);
CREATE INDEX I_THRRTCL_ELEMENT ON AuthorArticle (ArticleId);
CREATE TABLE Article (articleId INTEGER NOT NULL, PRIMARY KEY (articleId)) TYPE = innodb;
CREATE TABLE Author (authorId INTEGER NOT NULL, PRIMARY KEY (authorId)) TYPE = innodb;
CREATE TABLE AuthorArticle (AuthorId INTEGER, ArticleId INTEGER) TYPE = innodb;
CREATE INDEX I_THRRTCL_AUTHORID ON AuthorArticle (AuthorId);
CREATE INDEX I_THRRTCL_ELEMENT ON AuthorArticle (ArticleId);
3.2.12 Order By
由于关系型数据库并不保存records的顺序,因此为了保证集合类型的字段有一致的顺序,必须使用OrderBy annotation。缺省是采用identity values的升序。以下是个简单的例子:
Java代码
@OrderBy("lastName, firstName")
private Collection<Author> authors;
@OrderBy("lastName, firstName")
private Collection<Author> authors;
3.2.13 Map Key
JPA在OneToMany或者ManyToMany关系中支持Map类型的字段,关联的entities组成了Map的value。JPA在每个entity中挑选一个字段作为Map的key。MapKey annotation有一个name属性,用来指定被挑选作为key的字段名。如果没有指定name,那么会使用关联entity的identity字段。
3.2.14 Persistent Field Defaults
当某个字段没有使用以上介绍的annotations时,JPA对该字段采取以下的缺省行为:
被声明成static, transient, final的字段缺省是non-persistent。
以下类型的字段:primitive type, primitive wrapper type, java.lang.String, byte[], Byte[], char[], Character[], java.math.BigDecimal, java.math.BigInteger, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Timestamp, Serializable type 缺省时persistent,就像使用了Basic annotation一样。
Embeddable type缺省是persistent,就像使用了Embedded annotation一样。
以上以外的字段缺省是non-persistent。
3.2.15 Column
Column annotation 用来指定列的属性,它有以下可选属性:
String name: 列名,缺省是属性名。
String columnDefinition: 数据库中列的数据类型。只有当JPA vendor支持通过metadata创建表的时候,这个属性才被使用。
int length: 列的长度,这个属性通常也是在创建表的时候使用。也有的JPA vendor在flush之前通过这个属性验证数据。
int precision: 列的精度。
int scale: 列的小数范围。
boolean nullable: 列是否允许为null。缺省是true。
boolean insertable: 如果false,那么SQL 的insert语句中会忽略这个列。缺省是true。
boolean updatable: 如果false,那么SQL 的update语句中会忽略这个列。缺省是true。
String table: 指定secondary table的表名。
评论
1 楼
kevinhrw
2008-07-27
@GeneratedValue(strategy = GenerationType.AUTO, generator="uuid-string")
private String uuidString;
這樣寫有錯哦~~~
private String uuidString;
這樣寫有錯哦~~~
发表评论
-
EJB3 QL查询
2008-07-17 15:57 1552EJB3 QL查询 EJB3的查询语言是一种和SQL非常类似的 ... -
Table
2008-07-08 12:18 2024Table Table用来定义entity主表的name,ca ... -
Overview
2008-07-07 19:33 9481 Overview Apache OpenJPA是J ... -
EntityManagerFactory
2008-07-07 19:30 95574 EntityManagerFactory 4.1 Over ... -
Miscellaneous Features
2008-07-07 19:29 134410 Miscellaneous Features 10.1 ... -
Object Locking
2008-07-07 19:27 13518 Object Locking 8.1 Configurin ... -
Query
2008-07-07 19:26 15976 Query 6.1 JPQL Queries 6.1.1Q ... -
jpa继承关系详解
2008-07-07 19:07 82347 Inheritance 对象使用引用以便关联到其它 ... -
JNDI简介
2008-05-29 17:03 1711JNDI简介 & 简单示例 ... -
ejb2 和 ejb3的区别
2008-03-31 13:39 4250EJB 3 和EJB 2.1 的区别 从整个EJB 规范的 ...
相关推荐
"解决Android Studio Gradle Metadata特别慢的问题" Android Studio是Android应用程序开发的官方IDE,它提供了许多功能来帮助开发者快速构建和测试Android应用程序。然而,在使用Android Studio时,有时可能会遇到...
赠送jar包:metadata-extractor-2.6.2.jar; 赠送原API文档:metadata-extractor-2.6.2-javadoc.jar; 赠送源代码:metadata-extractor-2.6.2-sources.jar; 赠送Maven依赖信息文件:metadata-extractor-2.6.2.pom;...
赠送jar包:metadata-extractor-2.6.2.jar; 赠送原API文档:metadata-extractor-2.6.2-javadoc.jar; 赠送源代码:metadata-extractor-2.6.2-sources.jar; 赠送Maven依赖信息文件:metadata-extractor-2.6.2.pom;...
赠送jar包:spring-plugin-metadata-2.0.0.RELEASE.jar; 赠送原API文档:spring-plugin-metadata-2.0.0.RELEASE-javadoc.jar; 赠送源代码:spring-plugin-metadata-2.0.0.RELEASE-sources.jar; 赠送Maven依赖信息...
metadata-extractor-2.4.0.rar metadata-extractor-2.4.0.rar 获取 图片 exif 信息 使用方法: File jpegFile = new File("c:\\newchangetime.jpg"); Metadata metadata = JpegMetadataReader.readMetadata(jpeg...
`DatabaseMetaData` 是Java数据库连接(JDBC)API的一部分,它提供了关于数据库模式、特性以及元数据的详细信息。本篇文章将深入探讨如何利用`DatabaseMetaData`生成数据库的DLL(在关系型数据库中,DLL通常指的是...
"metadata-extractor-2.8.1" 是一个Java库,专门用于从各种图像和音频文件中提取元数据。这个库是由Dave Coffin创建并维护的,它支持大量的文件格式,包括JPEG、TIFF、PNG、PDF等。元数据通常包含关于文件的详细信息...
This standard specifies static High Dynamic Range (HDR) metadata extensions using an additional InfoFrame and EDID CTA data block, replacing previously reserved codes in Table 5 and Table 46 of CTA-...
标题中的"jquery.metadata.1.0_javascript_jquery_"表明我们关注的是一个jQuery插件,名为jQuery Metadata。这个插件是jQuery库的一个扩展,用于解析HTML元素中的元数据(metadata)。元数据通常存储在元素的自定义...
"kotlin-metadata"库是Kotlin生态系统中的一个重要组成部分,它专门用于处理Kotlin编译器生成的元数据。元数据在编译过程中记录了关于源代码的各种信息,比如类型信息、注解、函数签名等,这对于反射和编译时代码...
Flink 无法获取 Kafka Topic Metadata 异常及解决 一、问题现象 在使用 Kafka 0.11.0.1 和 Flink 1.4 进行实时计算时,Flink 无法获取 Kafka Topic Metadata,报以下异常:org.apache.kafka.common.errors....
`sql_metadata` 是一个Python库,专注于处理SQL数据库的相关元数据。这个库的版本是1.10.0,以`.whl`格式提供,这是一个Python的二进制分发包,用户可以直接安装,无需编译。`.whl`文件的命名遵循PEP 427,表明该...
SAP.Middleware.Connector.RfcCommunicationException:“destination XXXX failed when calling RFC_METADATA_GET -- see log for details” 猜测的原因: 老的DLL库在获取接口实例时,会触发“RFC_METADATA_GET”...
在本文中,我们将深入探讨Laravel开发中的"metadata"概念,以及如何在实际项目中运用这一功能。"metadata"在编程领域通常指的是关于数据的数据,它提供了额外的信息,帮助我们更好地理解和处理数据。在Laravel框架中...
《jQuery Metadata插件详解及其应用》 在Web开发领域,jQuery作为一个强大的JavaScript库,极大地简化了DOM操作,事件处理和Ajax交互。而jQuery Metadata插件是jQuery生态系统中的一个重要组件,它提供了一种灵活的...
在Java编程中,元数据(Metadata)是指关于数据的数据,它提供有关文件、数据库记录、类、方法等的附加信息,但不直接构成这些实体的实际内容。元数据可以帮助理解和处理这些对象,例如,图片的元数据可能包含拍摄...
赠送jar包:imageio-metadata-3.1.1.jar; 赠送原API文档:imageio-metadata-3.1.1-javadoc.jar; 赠送源代码:imageio-metadata-3.1.1-sources.jar; 赠送Maven依赖信息文件:imageio-metadata-3.1.1.pom; 包含...
《jQuery Metadata插件详解及其应用》 在JavaScript的世界里,jQuery库以其易用性和强大的功能深受开发者喜爱。而jQuery Metadata插件是jQuery生态系统中的一个重要组件,它允许开发者从HTML元素中提取元数据...
"metadata-extractor-2.11.0源码及Jar包"是一个针对图像和文档元数据提取的Java库,主要用于解析各种文件格式的元数据。这个包包含了两个关键组件:`metadata-extractor-2.11.0.jar`是编译好的二进制库,可以直接在...
在IT领域,尤其是在图像处理和数字媒体管理中,"mediautil+metadata-extractor"是一个用于提取和查看EXIF(Exchangeable Image File Format)信息的工具。这个工具包含两个核心组件:`meduautil-1.0.jar`和`metadata...