Apache Olingo - JPA Model sapmle

1 数据模型

表关系如图



定义Product Model

@Entity
@Table(name = "ESPM_PRODUCT")
@NamedQueries({
    @NamedQuery(name = "Product.getProductByProductId", query = "SELECT p FROM Product p where p.productId = :productId"),
    @NamedQuery(name = "Product.getAllProducts", query = "SELECT p FROM Product p"),
    @NamedQuery(name = "Product.getProductByCategory", query = "SELECT p FROM Product p WHERE p.category = :category")
})
public class Product {

    transient private static Map<String, BigDecimal> prices = null;

    @Id
    @Column(name = "PRODUCT_ID", length = 10)
    private String productId;

    private String name;

    @Column(name = "SHORT_DESCRIPTION")
    private String shortDescription;

    @Column(name = "LONG_DESCRIPTION")
    private String longDescription;

    @Column(length = 40)
    private String category;

    @Column(name = "CATEGORY_NAME", length = 40)
    private String categoryName;

    @Column(name = "QUANTITY_UNIT", length = 3)
    private String quantityUnit;

    @Column(name = "WEIGHT", precision = 13, scale = 3)
    private BigDecimal weight;

    @Column(name = "WEIGHT_UNIT", length = 3)
    private String weightUnit;

    @Column(precision = 23, scale = 3)
    private BigDecimal price;

    @Column(name = "CURRENCY_CODE", length = 5)
    private String currencyCode = "EUR";

    @Column(name = "DIMENSION_WIDTH", precision = 13, scale = 4)
    private BigDecimal dimensionWidth;

    @Column(name = "DIMENSION_DEPTH", precision = 13, scale = 4)
    private BigDecimal dimensionDepth;

    @Column(name = "DIMENSION_HEIGHT", precision = 13, scale = 4)
    private BigDecimal dimensionHeight;

    @Column(name = "DIMENSION_UNIT", length = 3)
    private String dimensionUnit;

    @Column(name = "PICTURE_URL")
    private String pictureUrl;

    @Column(name = "SUPPLIER_ID", length = 10)
    private String supplierId;

    @OneToOne  //OData Navigation
    private Supplier supplier;

    @OneToMany(mappedBy = "product", targetEntity = CustomerReview.class, fetch = FetchType.EAGER)  //OData Navigation
    private List<CustomerReview> reviews;

    public Product() {
        this.reviews = new ArrayList<CustomerReview>();
    }

    // set & get method for fields
    // set&get method for Customer Review
    public void addReview(CustomerReview review) {
        this.reviews.add(review);
    }

    public List<CustomerReview> getReviews() {
        return this.reviews;
    }
    //根据id获取price
    static BigDecimal getPrice(String productId) {
        if (prices == null) {
            updatePrices();
        }
        return prices.get(productId);
    }
    //取出所有product的price
    private static void updatePrices() {
        EntityManagerFactory emf = Utility.getEntityManagerFactory();
        EntityManager em = emf.createEntityManager();
        try {
            List<Product> products = em.createQuery("SELECT p FROM Product p", Product.class).getResultList();
            prices = new HashMap<String, BigDecimal>();
            for (Product p : products) {
                prices.put(p.getProductId(), p.getPrice());
            }
        } finally {
            em.close();
        }
    }
  //无效的price
    private static void invalidatePrices() {
        if (prices != null) {
            prices.clear();
        }
        prices = null;
    }
  //更新后,取出product text
    @PostLoad
    private void postLoad() {
        EntityManagerFactory emf = Utility.getEntityManagerFactory();
        EntityManager em = emf.createEntityManager();
        try {
            ProductText productText = getProductText(em);
            if (productText != null) {
                this.name = productText.getName();
                this.shortDescription = productText.getShortDescription();
                this.longDescription = productText.getLongDescription();
            } else {
                this.name = "";
                this.shortDescription = "";
                this.longDescription = "";
            }
        } finally {
            em.close();
        }
    }
  //更新前先更新text表
    @PrePersist
    @PreUpdate
    private void persist() {
        EntityManagerFactory emf = Utility.getEntityManagerFactory();
        EntityManager em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            ProductText productText = getProductText(em);
            if (productText == null) {
                // INSERT
                productText = new ProductText();
                productText.setProductId(this.getProductId());
                productText.setLanguage("EN");
                productText.setName(this.name);
                productText.setShortDescription(this.shortDescription);
                productText.setLongDescription(this.longDescription);
                em.persist(productText);
            } else {
                // UPDATE
                productText.setName(this.name);
                productText.setShortDescription(this.shortDescription);
                productText.setLongDescription(this.longDescription);
            }

            em.getTransaction().commit();
        } finally {
            // ProductCategory.invalidateNumbers();
            invalidatePrices();
            em.close();
        }
    }
  //取text表的描述
    private ProductText getProductText(EntityManager em) {
        TypedQuery<ProductText> query = em.createQuery(
                "SELECT p FROM ProductText p WHERE p.productId = :productId AND p.language = :language",
                ProductText.class);
        try {
            return query.setParameter("productId", this.getProductId()).setParameter("language", "EN")
                    .getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    public Map<String, String> getProductReportMap() {

        Map<String, String> productMap = new LinkedHashMap<>(2);
        productMap.put("shortDescription", shortDescription);
        productMap.put("price", String.valueOf(price));

        return productMap;
    }
}

定义Supplier Model

@Entity
@Table(name = "ESPM_SUPPLIER")
@NamedQueries({
    @NamedQuery(name = "Supplier.getAllSuppliers", query = "SELECT s FROM Supplier s"),
    @NamedQuery(name = "Supplier.getSupplierBySupplierId", query = "SELECT s FROM Supplier s WHERE s.supplierId= :supplierId")
})
public class Supplier {
    /* Supplier ids are generated within a number range starting with 2 */
    @TableGenerator(name = "SupplierGenerator", table = "ESPM_ID_GENERATOR", pkColumnName = "GENERATOR_NAME", valueColumnName = "GENERATOR_VALUE", pkColumnValue = "Customer", initialValue = 100000000, allocationSize = 100)
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "SupplierGenerator")
    @Column(name = "SUPPLIER_ID", length = 10)
    private String supplierId;

    @Column(name = "EMAIL_ADDRESS", unique = true)
    private String emailAddress;

    @Column(name = "PHONE_NUMBER", length = 30)
    private String phoneNumber;

    @Column(name = "CITY", length = 40)
    private String city;

    @Column(name = "POSTAL_CODE", length = 10)
    private String postalCode;

    @Column(name = "STREET", length = 60)
    private String street;

    @Column(name = "HOUSE_NUMBER", length = 10)
    private String houseNumber;

    @Column(name = "COUNTRY", length = 3)
    private String country;

    @Column(name = "SUPPLIER_NAME", length = 80)
    private String supplierName;

    public String getSupplierId() {
        return supplierId;
    }
    // set & get method

定义CustomerReview Model

@Entity
@Table(name = "ESPM_EXTENSION_CUSTOMER_REVIEW")
@NamedQuery(name = "CustomerReview.getAllCustomerReviews", query = "SELECT cr FROM CustomerReview cr")
public class CustomerReview implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    @Column(name = "CUSTOMER_REVIEW_ID", length = 16)
    private String customerReviewId;

    @Column(name = "COMMENT", length = 1024)
    private String comment;

    @Column(name = "RATING")
    private int rating;
    
    @Column(name = "PRODUCT_ID", length = 10)
    private String productId;

    @Column(name = "DATE_OF_CREATION")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar creationDate;

    @Column(name = "FIRST_NAME", length = 40)
    private String firstName;

    @Column(name = "LAST_NAME", length = 40)
    private String lastName;

    @ManyToOne(optional=false)
    private Product product;
    
    public CustomerReview() {
        super();
    }

定义SalesOrderHeader Model

@Entity
@Table(name = "ESPM_SALES_ORDER_HEADER")
@NamedQueries({
    @NamedQuery(name = "SalesOrderHeader.getSOHBySaledOrderId", query = "SELECT soh FROM SalesOrderHeader soh WHERE soh.salesOrderId= :salesOrderId"),
    @NamedQuery(name = "SalesOrderHeader.getSOHByCustomerId", query = "SELECT soh FROM SalesOrderHeader soh WHERE soh.customerId= :customerId")
})
public class SalesOrderHeader {

    /* Sales order ids are generated within a number range starting with 5 */
    @TableGenerator(name = "SalesOrderGenerator", table = "ESPM_ID_GENERATOR", pkColumnName = "GENERATOR_NAME", valueColumnName = "GENERATOR_VALUE", pkColumnValue = "SalesOrder", initialValue = 500000000, allocationSize = 100)
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "SalesOrderGenerator")
    @Column(name = "SALES_ORDER_ID", length = 10)
    private String salesOrderId;

    @Column(name = "CUSTOMER_ID", length = 10)
    private String customerId;

    @Column(name = "CURRENCY_CODE", length = 5)
    private String currencyCode = "EUR";

    @Column(name = "GROSS_AMOUNT", precision = 15, scale = 3)
    private BigDecimal grossAmount;

    @Column(name = "NET_AMOUNT", precision = 15, scale = 3)
    private BigDecimal netAmount;

    @Column(name = "TAX_AMOUNT", precision = 15, scale = 3)
    private BigDecimal taxAmount;

    @Column(name = "LIFE_CYCLE_STATUS", length = 1, nullable = false)
    private String lifeCycleStatus;

    @Column(name = "LIFE_CYCLE_STATUS_NAME", nullable = false)
    private String lifeCycleStatusName;

    @Column(name = "CREATED_AT")
    @Temporal(TemporalType.DATE)
    private Calendar createdAt;

    @Column(name = "INVOICE_LINK", length = 200)
    private String invoiceLink;

    @OneToOne
    private Customer customer;

    @OneToMany(mappedBy = "salesOrderHeader", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<SalesOrderItem> salesOrderItems;

    public SalesOrderHeader() {
        this.salesOrderItems = new ArrayList<SalesOrderItem>();
    }

    //set & get method

    @PrePersist
    private void persist() {
        Calendar cal = Calendar.getInstance();
        Date date = new Date();
        cal.setTime(date);
        this.lifeCycleStatus = "N";
        this.lifeCycleStatusName = "New";
        int itemNumber = 10;
        this.netAmount = new BigDecimal("0.00");
        this.taxAmount = new BigDecimal("0.00");
        this.grossAmount = new BigDecimal("0.00");
        this.createdAt = cal;
        for (SalesOrderItem item : salesOrderItems) {
            item.setSalesOrderId(this.getSalesOrderId());
            item.setItemNumber(itemNumber);
            itemNumber += 10;
            item.persist();
            this.netAmount = this.netAmount.add(item.getNetAmount())
                    .setScale(3);
            this.taxAmount = this.taxAmount.add(item.getTaxAmount())
                    .setScale(3);
            this.grossAmount = this.grossAmount.add(item.getGrossAmount())
                    .setScale(3);
        }
    }

}

定义SalesOrderItem Model

@Entity
@Table(name = "ESPM_SALES_ORDER_ITEM")
@NamedQueries({
    @NamedQuery(name = "SalesOrderItem.getSOIBySalesOrderItemId", query = "SELECT soi FROM SalesOrderItem soi WHERE soi.id.salesOrderId= :id"),
    @NamedQuery(name = "SalesOrderItem.getSOIByCurrencyCode", query = "SELECT soi FROM SalesOrderItem soi WHERE soi.currencyCode = :currencyCode")
})
public class SalesOrderItem {

    private static final BigDecimal TAX_AMOUNT_FACTOR = new BigDecimal("0.19");
    private static final BigDecimal GROSS_AMOUNT_FACTOR = new BigDecimal("1.19");

    @EmbeddedId
    private SalesOrderItemId id;

    @Column(name = "PRODUCT_ID", length = 10)
    private String productId;

    @Column(name = "CURRENCY_CODE", length = 5)
    private String currencyCode = "EUR";

    @Column(name = "GROSS_AMOUNT", precision = 15, scale = 3)
    private BigDecimal grossAmount;

    @Column(name = "NET_AMOUNT", precision = 15, scale = 3)
    private BigDecimal netAmount;

    @Column(name = "TAX_AMOUNT", precision = 15, scale = 3)
    private BigDecimal taxAmount;

    @Column(precision = 13, scale = 3)
    private BigDecimal quantity;

    @Column(name = "QUANTITY_UNIT", length = 3)
    private String quantityUnit = "EA";

    @Column(name = "DELIVERY_DATE")
    @Temporal(TemporalType.DATE)
    private Calendar deliveryDate;

    @OneToOne
    private Product product;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name = "SALES_ORDER_ITEM_ID", referencedColumnName = "SALES_ORDER_ID", insertable = false, updatable = false)
    private SalesOrderHeader salesOrderHeader;

    public SalesOrderItem() {
        this.id = new SalesOrderItemId();
    }

    public SalesOrderItem(String salesOrderId, int itemNumber) {
        this.id = new SalesOrderItemId(salesOrderId, itemNumber);
    }

    // set & get method

    void persist() {
        BigDecimal price = Product.getPrice(this.getProductId());
        if (price == null) {
            return;
        }
        this.netAmount = price.multiply(this.getQuantity()).setScale(3);
        this.taxAmount = this.netAmount.multiply(TAX_AMOUNT_FACTOR).setScale(3);
        this.grossAmount = this.netAmount.multiply(GROSS_AMOUNT_FACTOR)
                .setScale(3);
    }

}

定义SalesOrderItemId Model

@Embeddable
public class SalesOrderItemId implements Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "SALES_ORDER_ITEM_ID", length = 10)
    private String salesOrderId;

    @Column(name = "ITEM_NUMBER")
    private int itemNumber;

    public SalesOrderItemId() {
    }

    public SalesOrderItemId(String salesOrderId, int itemNumber) {
        this.salesOrderId = salesOrderId;
        this.itemNumber = itemNumber;
    }

    //set & get method
    @Override
    public int hashCode() {
        return salesOrderId.hashCode() + itemNumber;
    }

    @Override //判断itemId相等
    public boolean equals(Object obj) {
        return ((obj instanceof SalesOrderItemId)
                && this.salesOrderId.equals(((SalesOrderItemId) obj)
                        .getSalesOrderId()) && (this.itemNumber == ((SalesOrderItemId) obj)
                    .getItemNumber()));
    }

}

定义Customer Moel

@Entity
@Table(name = "ESPM_CUSTOMER")
@NamedQueries({
    @NamedQuery(name = "Customer.getCustomerByEmailAddress", query = "SELECT c FROM Customer c WHERE c.emailAddress = :emailAddress"),
    @NamedQuery(name = "Customer.getCustomerByCustomerId", query = "SELECT cid FROM Customer cid WHERE cid.customerId= :customerId"),
    @NamedQuery(name = "Customer.getAllCustomers", query = "SELECT c FROM Customer c")
})
public class Customer {

    /* Customer ids are generated within a number range starting with 1 */
    @TableGenerator(name = "CustomerGenerator", table = "ESPM_ID_GENERATOR", pkColumnName = "GENERATOR_NAME", valueColumnName = "GENERATOR_VALUE", pkColumnValue = "Customer", initialValue = 100000000, allocationSize = 100)
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "CustomerGenerator")
    @Column(name = "CUSTOMER_ID", length = 10)
    private String customerId;

    @Column(name = "EMAIL_ADDRESS", unique = true)
    private String emailAddress;

    @Column(name = "PHONE_NUMBER", length = 30)
    private String phoneNumber;

    @Column(name = "FIRST_NAME", length = 40)
    private String firstName;

    @Column(name = "LAST_NAME", length = 40)
    private String lastName;

    @Column(name = "DATE_OF_BIRTH", nullable = false)
    @Temporal(TemporalType.DATE)
    private Calendar dateOfBirth;

    @Column(name = "CITY", length = 40)
    private String city;

    @Column(name = "POSTAL_CODE", length = 10)
    private String postalCode;

    @Column(name = "STREET", length = 60)
    private String street;

    @Column(name = "HOUSE_NUMBER", length = 10)
    private String houseNumber;

    @Column(name = "COUNTRY", length = 3)
    private String country;

    //set & get method

    public Map<String, String> getCustomerReportData() {

        Map<String, String> customerMapData = new LinkedHashMap<String, String>(7);
        customerMapData.put("firstName", firstName);
        customerMapData.put("lastName", lastName);
        customerMapData.put("houseNumber", houseNumber);
        customerMapData.put("emailAddress", emailAddress);
        customerMapData.put("phoneNumber", phoneNumber);
        customerMapData.put("city", city);
        customerMapData.put("street", street);
        customerMapData.put("country", country);
        return customerMapData;

    }

定义ProductCategory Model

@Entity
@Table(name = "ESPM_PRODUCT_CATEGORY")
@NamedQueries({
    @NamedQuery(name = "ProductCategory.getAllProductCategories", query = "SELECT pc FROM ProductCategory pc"),
    @NamedQuery(name = "ProductCategory.getProductCategoryByCategory", query = "SELECT pc FROM ProductCategory pc WHERE pc.category= :category"),
    @NamedQuery(name = "ProductCategory.getProductCategoryByCategoryName", query = "SELECT pc FROM ProductCategory pc WHERE pc.categoryName= :categoryName")
})
public class ProductCategory {

    @Id
    @Column(length = 40)
    private String category;

    @Column(name = "CATEGORY_NAME", length = 40)
    private String categoryName;

    @Column(name = "MAIN_CATEGORY", length = 40)
    private String mainCategory;

    @Column(name = "MAIN_CATEGORY_NAME", length = 40)
    private String mainCategoryName;

    @Column(name = "NUMBER_OF_PRODUCTS")
    long numberOfProducts;

2 配置

配置persistence.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="test-web" transaction-type="RESOURCE_LOCAL">

          <class>model.Customer</class>
          <class>model.CustomerReview</class>
          <class>model.Product</class>
          <class>model.ProductCategory</class>
          <class>model.ProductText</class>
          <class>model.SalesOrderHeader</class>
          <class>model.SalesOrderItem</class>
          <class>model.SalesOrderItemId</class>
          <class>model.Stock</class>
          <class>model.Supplier</class>
          
          <properties>
                 <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
                 <property name="javax.persistence.jdbc.user" value="root"/>
                 <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
          </properties>
       </persistence-unit>
</persistence>

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
    id="WebApp_ID" version="3.0">  
    <display-name>RestProjectTest</display-name>  
    <servlet>  
        <servlet-name>ODataServlet</servlet-name>  
        <servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>  
        <init-param>  
            <param-name>javax.ws.rs.Application</param-name>  
            <param-value>org.apache.olingo.odata2.core.rest.app.ODataApplication</param-value>  
        </init-param>  
        <init-param>  
            <param-name>org.apache.olingo.odata2.service.factory</param-name>  
            <param-value>web.EmployeeListServiceFactory</param-value>  
        </init-param>  
        <load-on-startup>2</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>ODataServlet</servlet-name>  
        <url-pattern>/espm.svc/*</url-pattern>  
    </servlet-mapping>
    
    <resource-ref>
        <res-ref-name>jdbc/DefaultDB</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
    </resource-ref>
    
    <servlet>
        <description></description>
        <display-name>StartupServlet</display-name>
        <servlet-name>StartupServlet</servlet-name>
        <servlet-class>web.StartupServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>  
</web-app>   

创建EmployeeListServiceFactory类

public class EmployeeListServiceFactory extends ODataJPAServiceFactory {

  private static final String PERSISTENCE_UNIT_NAME = "test-web";

  @Override
  public ODataJPAContext initializeODataJPAContext()

      throws ODataJPARuntimeException {

        ODataJPAContext oDatJPAContext = this.getODataJPAContext();
        EntityManagerFactory emf;
    
        try {   
//        EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); 
          emf = JpaEntityManagerFactory.getEntityManagerFactory();  
          oDatJPAContext.setEntityManagerFactory(emf);  
          oDatJPAContext.setPersistenceUnitName(PERSISTENCE_UNIT_NAME); 
          oDatJPAContext.setJPAEdmExtension(new EspmProcessingExtension());
          oDatJPAContext.setJPAEdmMappingModel("EspmEdmMapping.xml");
          return oDatJPAContext;
        } catch (Exception e) { 
          throw new RuntimeException(e);    
        }
  }
}

创建EspmProcessingExtension,添加Operation

public class EspmProcessingExtension implements JPAEdmExtension {

    /**
     * Register function imports.
     */
    @Override
    public void extendWithOperation(JPAEdmSchemaView view) {
        view.registerOperations(CustomerProcessor.class, null);
        view.registerOperations(SalesOrderProcessor.class, null);
        view.registerOperations(CustomerReviewProcessor.class, null);
    }

定义CustomerProcessor,添加getCustomerByEmailAddress方法

public class CustomerProcessor {

    @SuppressWarnings("unchecked")
    @EdmFunctionImport(name = "GetCustomerByEmailAddress", entitySet = "Customers", returnType = @ReturnType(type = Type.ENTITY, isCollection = true))
    public List<Customer> getCustomerByEmailAddress(
            @EdmFunctionImportParameter(name = "EmailAddress") String emailAddress) throws ODataException {
        EntityManagerFactory emf = Utility.getEntityManagerFactory();
        EntityManager em = emf.createEntityManager();
        List<Customer> custList = null;
        try {

            Query query = em.createNamedQuery("Customer.getCustomerByEmailAddress");
            query.setParameter("emailAddress", emailAddress);

            try {
                custList = query.getResultList();
                return custList;
            } catch (NoResultException e) {
                throw new ODataApplicationException("No matching customer with Email Address:" + emailAddress,
                        Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST, e);
            }
        } finally {
            em.close();
        }
    }
}

定义CustomerReviewProcessor类,添加createCustomerReview方法

public class CustomerReviewProcessor {


    @SuppressWarnings("unchecked")
    @EdmFunctionImport(name = "CreateCustomerReview", entitySet = "CustomerReviews", returnType = @ReturnType(type = Type.ENTITY, isCollection = false))
    public CustomerReview createCustomerReview(@EdmFunctionImportParameter(name = "ProductId") String productId,
            @EdmFunctionImportParameter(name = "FirstName") String firstName,
            @EdmFunctionImportParameter(name = "LastName") String lastName,
            @EdmFunctionImportParameter(name = "Rating") String rating,
            @EdmFunctionImportParameter(name = "CreationDate") String creationDate,
            @EdmFunctionImportParameter(name = "Comment") String comment) throws ODataException, ParseException {
        EntityManagerFactory emf = Utility.getEntityManagerFactory();
        EntityManager em = emf.createEntityManager();
        Product prod = null;
        CustomerReview customerReview = null;
        try {
            em.getTransaction().begin();
            prod = em.find(Product.class, productId);
            try {
                customerReview = new CustomerReview();
                customerReview.setComment(comment);
                Calendar cal = Calendar.getInstance();
                cal.setTime(new Date(Long.parseLong(creationDate)));
                customerReview.setCreationDate(cal);
                customerReview.setFirstName(firstName);
                customerReview.setLastName(lastName);
                customerReview.setRating(Integer.parseInt(rating));
                customerReview.setProductId(productId);
                customerReview.setProduct(prod);
                em.persist(customerReview);
                if (prod != null) {
                    prod.addReview(customerReview);
                }
                em.getTransaction().commit();
                return customerReview;
            } catch (NoResultException e) {
                throw new ODataApplicationException("Error creating customer review:", Locale.ENGLISH,
                        HttpStatusCodes.BAD_REQUEST, e);
            }
        } finally {
            em.close();
        }
    }
}

得到的metadata如下


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容