2016-10-12 2 views
2

В настоящее время я работаю над сервисом odata на основе JPA/Olingo. Используемая версия Olingo - 2.0.7. Используемая реализация JPA - eclipselink version 2.5.1. Взаимодействие OneToMany связано с двумя объектами (Company, Page). Запрос компании из службы (например,/odata/v2/Companies) без расширения $ expand работает нормально. То же самое для запроса страниц. Запросы страниц и расширение CompanyDetails прекрасно работают. Как-то запрашивая компанию и расширяя связанные страницы (например,/odata/v2/Companies? $ Expand = Pages) возвращает массив нулевого размера для страниц, хотя при вызове отложенной ссылки (например,/odata/v2/Companies ('P')/Pages) в сущности компании возвращает массив страниц, как ожидалось.

Вот мой persistence.xml (ommiting другие еще не протестированные объекты):

<?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 и переопределяю initializeODat Метод aJPAContext:

@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> 
+0

Удалось решить эту проблему? В настоящее время я сталкиваюсь с одной и той же проблемой и не знаю, как ее решить ... – 3dDi92

+0

Нет, я не решал ее до сих пор. Я был занят другими задачами, но попытаюсь решить его снова, когда у меня будет свободное время. Тем временем мы просто избежим использования ключевого слова $ expand в нашем проекте, который жаль. – defect

+0

Я уже нашел обходной путь, но этот, как-то работает только для тестовых данных, которые генерируются бэкэнд. В вашем случае вам нужно будет определить конкретный метод в вашем классе компании, чтобы добавить одну страницу на страницы списка. После того, как новая страница сохранилась, вы в основном должны вызвать родительский набор данных (компания) и добавить новую страницу persist. Тем не менее он работает только для моих тестовых данных, а не в продуктивной версии, и я думал, что это будет обрабатываться инфраструктурой JPA ... – 3dDi92

ответ

1

Я тестировал различные решения этой проблемы, которые уже обсуждались в замечания моего первоначального сообщения:

  • @Cache (type = CacheType.NONE): согласно документации EclispeLink (https://eclipse.org/eclipselink/api/2.0/org/eclipse/persistence/config/CacheType.html) использование этой аннотации не рекомендуется.

  • регистрирует класс PostPersistListener с классом страницы с использованием @EntityListeners и выполняет «invalidateAll» в методе, аннотированном с @PostPersist. Результат оказался ненадежным.

  • @Cache (isolation = CacheIsolationType.ISOLATED): Эта аннотация делает то, что мне нужно.

Так что проблема на данный момент решена. Думал, что неплохо документировать его для тех, кто испытывает ту же проблему. (И для меня, чтобы запомнить это в следующий раз ;-))

Смежные вопросы