2

我目前正在开发基于 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>
4

1 回答 1

1

我针对这个问题测试了不同的解决方案,这些解决方案已经在我的原始帖子的评论中讨论过:

  • @Cache(type=CacheType.NONE):根据 EclispeLink ( https://eclipse.org/eclipselink/api/2.0/org/eclipse/persistence/config/CacheType.html ) 的文档,不鼓励使用此注解.

  • 使用@EntityListeners 向Page 类注册一个PostPersistListener 类,并在使用@PostPersist 注释的方法中执行“invalidateAll”。结果并不可靠。

  • @Cache(isolation=CacheIsolationType.ISOLATED): 这个注解可以满足我的需要。

所以我的问题现在已经解决了。认为为遇到相同问题的任何人记录它是一个好主意..(让我下次记住它;-))

于 2016-12-05T10:35:09.790 回答