我目前正在开发基于 JPA/Olingo 的 odata 服务。使用的 Olingo 版本是 2.0.7。使用的 JPA 实现是 eclipselink 版本 2.5.1。有两个实体通过 OneToMany 关系连接(公司、页面)。从服务中请求公司(例如 /odata/v2/Companies)而不使用 $expand 可以正常工作。请求页面也是如此。请求页面和扩展 CompanyDetails 也可以正常工作。以某种方式请求公司并扩展相关页面(例如 /odata/v2/Companies?$expand=Pages)会为页面返回一个大小为零的数组,尽管在调用延迟链接时(例如 /odata/v2/Companies('P') /Pages) 在公司实体中按预期返回页面数组。
这是我的 persistence.xml(省略其他尚未测试的实体):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="s.h.backend"
transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>c.p.s.h.data.Company</class>
...
<class>c.p.s.h.data.Page</class>
...
<properties>
<property name="eclipselink.ddl-generation"
value="create-tables" />
<property name="eclipselink.logging.level" value="INFO" />
<property name="eclipselink.jpql.parser"
value="org.eclipse.persistence.queries.ANTLRQueryBuilder" />
</properties>
</persistence-unit>
</persistence>
我的公司类如下所示:
@Entity
@Table(name = "HUM_COMPANY")
public class Company {
private static final Logger log =
LoggerFactory.getLogger(Company.class);
@Id
private String id;
@Column
private String datacenterUrl;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "company", cascade =
CascadeType.ALL)
@CascadeOnDelete
private List<Page> pages;
@Temporal(TemporalType.TIMESTAMP)
@Column(insertable = false, updatable = false)
private Date modified;
@Temporal(TemporalType.TIMESTAMP)
@Column(insertable = false, updatable = false)
private Date created;
@PrePersist
public void prePersist() {
Date now = new Date();
created = now;
modified = now;
}
@PreUpdate
public void preUpdate() {
modified = new Date();
}
public Date getModified() {
return modified;
}
public void setModified(Date modified) {
log.debug("Olingo trying to set date {}", modified);
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
log.debug("Olingo trying to set date {}", created);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDatacenterUrl() {
return datacenterUrl;
}
public void setDatacenterUrl(String datacenterUrl) {
this.datacenterUrl = datacenterUrl;
}
public List<Page> getPages() {
return pages;
}
public void setPages(List<Page> pages) {
this.pages = pages;
}
}
我的页面类如下所示:
@Entity
@Table(name = "HUM_PAGE")
public class Page implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Page.class);
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false, name = "page_name")
private String name;
@Column
private String description;
@OneToOne
private Context context;
@ManyToOne(cascade = CascadeType.REFRESH)
@JoinColumn(name = "company_id", nullable = false)
private Company company;
@Temporal(TemporalType.TIMESTAMP)
@Column(nullable = false)
private Date modified;
@Temporal(TemporalType.TIMESTAMP)
@Column(nullable = false)
private Date created;
@PrePersist
public void prePersist() {
Date now = new Date();
created = now;
modified = now;
}
@PreUpdate
public void preUpdate() {
modified = new Date();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getId() {
return id;
}
public Date getModified() {
return modified;
}
public Date getCreated() {
return created;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public void setId(Long id) {
log.debug("Olingo trying to set Id {}", id);
}
public void setModified(Date modified) {
log.debug("Olingo trying to set date {}", modified);
}
public void setCreated(Date created) {
log.debug("Olingo trying to set date {}", created);
}
}
我正在扩展 ODataJPAServiceFactory 并覆盖 initializeODataJPAContext 方法:
@Override
public ODataJPAContext initializeODataJPAContext() throws
ODataJPARuntimeException {
ODataJPAContext oDataJPAContext = getODataJPAContext();
try {
oDataJPAContext.setEntityManagerFactory(JpaEntityManagerFactory.getEntityManagerFactory());
oDataJPAContext.setPersistenceUnitName(JpaEntityManagerFactory.PERSISTENCE_UNIT_NAME);
oDataJPAContext.setJPAEdmMappingModel("HumEdmMapping.xml");
} catch (NamingException | SQLException e) {
throw new ODataRuntimeException(e);
}
return oDataJPAContext;
}
EntityManagerFactory 创建如下:
public static synchronized EntityManagerFactory
getEntityManagerFactory()
throws NamingException, SQLException {
if (entityManagerFactory == null) {
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(DATA_SOURCE_NAME);
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(PersistenceUnitProperties.NON_JTA_DATASOURCE,
ds);
entityManagerFactory = Persistence.createEntityManagerFactory(
PERSISTENCE_UNIT_NAME, properties);
}
return entityManagerFactory;
}
我的映射文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<JPAEDMMappingModel
xmlns="http://www.apache.org/olingo/odata2/jpa/processor/api/model/mapping">
<PersistenceUnit name="s.h.backend">
<JPAEntityTypes>
<JPAEntityType name="Company">
<EDMEntityType>Company</EDMEntityType>
<EDMEntitySet>Companies</EDMEntitySet>
<JPAAttributes>
<JPAAttribute name="created">Created</JPAAttribute>
<JPAAttribute
name="datacenterUrl">DatacenterUrl</JPAAttribute>
<JPAAttribute name="id">Id</JPAAttribute>
<JPAAttribute name="modified">Modified</JPAAttribute>
</JPAAttributes>
<JPARelationships>
<JPARelationship
name="pages">Pages</JPARelationship>
</JPARelationships>
</JPAEntityType>
<JPAEntityType name="Page">
<EDMEntityType>Page</EDMEntityType>
<EDMEntitySet>Pages</EDMEntitySet>
<JPAAttributes>
<JPAAttribute name="created">Created</JPAAttribute>
<JPAAttribute name="name">Name</JPAAttribute>
<JPAAttribute
name="description">Description</JPAAttribute>
<JPAAttribute name="id">Id</JPAAttribute>
<JPAAttribute name="modified">Modified</JPAAttribute>
</JPAAttributes>
<JPARelationships>
<JPARelationship
name="company">Company</JPARelationship>
</JPARelationships>
</JPAEntityType>
...
</JPAEntityTypes>
<JPAEmbeddableTypes>
</JPAEmbeddableTypes>
</PersistenceUnit>
</JPAEDMMappingModel>