为什么$ expand在我的JPA/Olingo项目中无法正常工作 [英] Why is $expand not working correct in my JPA/Olingo project
问题描述
我目前正在研究基于JPA/Olingo的odata服务.使用的Olingo版本是2.0.7.使用的JPA实现是eclipselink 2.5.1版.有两个实体通过OneToMany关系连接(公司,页面).在没有$ expand的情况下从服务中请求公司(例如/odata/v2/Companies)可以正常工作.请求页面也一样.请求页面和扩展CompanyDetails也可以正常工作.以某种方式请求公司并扩展关联的页面(例如/odata/v2/Companies?$ expand = Pages),尽管在调用延迟链接时(例如/odata/v2/Companies('P') /Pages)返回预期的页面数组.
I am currently working on a JPA/Olingo based odata service. The Olingo version used is 2.0.7. The JPA implementation used is eclipselink version 2.5.1. There are two entities connected through a OneToMany relationship (Company, Page). Requesting the company from the service (e.g. /odata/v2/Companies) without an $expand works fine. The same for requesting the pages. Requesting pages and expanding the CompanyDetails works fine as well. Somehow requesting the company and expanding the associated pages (e.g. /odata/v2/Companies?$expand=Pages) returns a zero size array for the pages allthough when calling the deferred link (e.g. /odata/v2/Companies('P')/Pages) in the company entity returns the array of pages as expected.
这是我的persistence.xml(省略其他尚未测试的实体):
Here's my persistence.xml (ommiting other not yet tested entities):
<?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;
}
}
我的Page类如下:
@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方法:
I am extending the ODataJPAServiceFactory and override the initializeODataJPAContext method:
@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:
The EntityManagerFactory is created as follows:
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>
推荐答案
我针对此问题测试了不同的解决方案,这些解决方案已在我的原始帖子的评论中进行了讨论:
I tested different solutions for this issue which were already discussed in the comments of my original post:
@Cache(type=CacheType.NONE): according to the documentation of EclispeLink (https://eclipse.org/eclipselink/api/2.0/org/eclipse/persistence/config/CacheType.html) the use of this annotation is discouraged.
使用@EntityListeners向Page类注册PostPersistListener类,并在以@PostPersist注释的方法中执行"invalidateAll".结果不可靠.
registering a PostPersistListener class with the Page class using @EntityListeners and do an "invalidateAll" in the method annotated with @PostPersist. The result was not reliable.
@Cache(isolation = CacheIsolationType.ISOLATED):此注释可以满足我的需要.
@Cache(isolation=CacheIsolationType.ISOLATED): This annotation does what I need.
所以我的问题现在已经解决了.认为将其记录给遇到相同问题的任何人都是一个好主意.(对我来说,下次记住它是;-))
So my problem has been solved for now. Thought it's a good idea to document it for anyone experiencing the same issue.. (And for me to remember it the next time ;-))
这篇关于为什么$ expand在我的JPA/Olingo项目中无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!