【问题标题】:Broadleaf 5.2 - How do I set ProductOptions into a newly created Product via the API?Broadleaf 5.2 - 如何通过 API 将 ProductOptions 设置为新创建的产品?
【发布时间】:2018-04-27 01:12:33
【问题描述】:

问题

我看到产品“setProductOptions()”方法已被弃用,而“setProductOptionXrefs()”是首选方法。问题是我似乎找不到任何关于如何设置 ProductOptionXrefs 的示例。

我也在 Broadleaf“BroadleafCommerce-develop-5.2.x”和“DemoSite-broadleaf-5.2.2.1-GA”项目中寻找示例以梳理银河系为例。没有运气。

目标 (X)

我正在创建一个接收 JSON 对象并接受两个参数(categoryNameprice)的端点。

端点将:

  • 找到产品所属的类别。
  • 创建一个新的 Sku 对象并填充一些输入 wrapper 字段。
  • 创建一个新的 Product 对象并填充几个 包装器 字段。
  • 为这个新产品分配一个 ProductOption。
  • 保存产品。
  • 返回响应(用于 REST 响应)。

端点本身看起来像:

@RequestMapping(value = "/my_product", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public ProductWrapper addCSDLProduct(HttpServletRequest request, @RequestBody ProductWrapper wrapper,
                                 @RequestParam(value = "categoryName", required = true) String categoryName,
                                 @RequestParam(value = "price", required = true) double price) {

    Category category = null;
    List<Category> categories = catalogService.findCategoriesByName( categoryName );
    if ( categories != null && categories.size() > 0 ) {
        category = categories.get(0);
    }

    Sku defaultSku = catalogService.createSku();
    defaultSku.setRetailPrice(new Money( price ));
    defaultSku.setInventoryType( InventoryType.ALWAYS_AVAILABLE );
    defaultSku.setName( wrapper.getName() );
    defaultSku.setLongDescription( wrapper.getLongDescription() );
    defaultSku.setDescription( wrapper.getDescription() );
    defaultSku.setUrlKey( wrapper.getUrl() );
    defaultSku.setActiveStartDate( new Date() );

    Product product = catalogService.createProduct(ProductType.PRODUCT);
    product.setDefaultSku(defaultSku);        
    product.setUrl( wrapper.getUrl() );
    product.setCategory(category);  

    List<ProductOptionXref> productOptionXrefs = new ArrayList<ProductOptionXref>();
    List<ProductOption> allProductOptions = catalogService.readAllProductOptions();        
    if ( null != allProductOptions && allProductOptions.size() > 0 ) {
        for ( ProductOption po : allProductOptions ) {          
            String current = po.getName();
            if ( current.equalsIgnoreCase("Shirt Color") ) {
                ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
                productOptionXref.setProductOption(po);
                productOptionXrefs.add(productOptionXref);
            }               
        }
    }

    product.setProductOptionXrefs(productOptionXrefs);

    Product finalProduct = catalogService.saveProduct(product);
    Long newId = finalProduct.getId();

    ProductWrapper response;
    response = (ProductWrapper) context.getBean(ProductWrapper.class.getName());
    response.wrapDetails(product, request);
    response.setId(newId);

    return response;
}

我使用的输入对象(一个例子)是:

{
    "name": "This is the name of the product.",
    "description": "This is the description of the product.",
    "longDescription": "This is a long description of the product. Really long.",
    "url": "/this/is/the/url/of/the/product",
    "defaultSku": {
        "name": "This is the name of the product.",
        "active": true,
        "available": true,
        "inventoryType": "ALWAYS_AVAILABLE",
        "retailPrice": {
            "amount": 19.0,
            "currency": "USD"
        }
    }
}

catgoryName 为“商品”,价格为 19.00。

上面的这段代码当前返回一个“Not-null”错误:

非空属性引用瞬态值 - 瞬态实例 必须在当前操作之前保存: org.broadleafcommerce.core.catalog.domain.ProductOptionXrefImpl.product -> org.broadleafcommerce.core.catalog.domain.ProductImpl;嵌套异常是 java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException:非空属性 引用瞬态值 - 瞬态实例必须先保存 当前操作: org.broadleafcommerce.core.catalog.domain.ProductOptionXrefImpl.product -> org.broadleafcommerce.core.catalog.domain.ProductImpl

这很可能与我有关

if ( current.equalsIgnoreCase("Shirt Color") ) {
  ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
  productOptionXref.setProductOption(po);
  productOptionXrefs.add(productOptionXref);
}   

和/或

Product finalProduct = catalogService.saveProduct(product);

就在上面。

我可以(最终)找出“非空”错误,但我要问的问题是,是否有人有将 ProductOption 或 ProductOptionXref 添加到新创建的产品的示例?

谢谢

乔恩

[更新]

我想用解决方案更新我的问题,非常感谢@phillipuniverse 提供的示例/解释。

@RequestMapping(value = "/my_product", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public ProductWrapper addCSDLProduct(HttpServletRequest request, @RequestBody ProductWrapper wrapper,
                                 @RequestParam(value = "categoryName", required = true) String categoryName,
                                 @RequestParam(value = "price", required = true) double price) {

    Category category = null;
    List<Category> categories = catalogService.findCategoriesByName( categoryName );
    if ( categories != null && categories.size() > 0 ) {
        category = categories.get(0);
    }

    Sku defaultSku = catalogService.createSku();
    defaultSku.setRetailPrice(new Money( price ));
    defaultSku.setInventoryType( InventoryType.ALWAYS_AVAILABLE );
    defaultSku.setName( wrapper.getName() );
    defaultSku.setLongDescription( wrapper.getLongDescription() );
    defaultSku.setDescription( wrapper.getDescription() );
    defaultSku.setUrlKey( wrapper.getUrl() );
    defaultSku.setActiveStartDate( new Date() );

    Product product = catalogService.createProduct(ProductType.PRODUCT);
    product.setDefaultSku(defaultSku);        
    product.setUrl( wrapper.getUrl() );
    product.setCategory(category);  

    List<ProductOptionXref> productOptionXrefs = new ArrayList<ProductOptionXref>();
    List<ProductOption> allProductOptions = catalogService.readAllProductOptions();        
    if ( null != allProductOptions && allProductOptions.size() > 0 ) {
        for ( ProductOption po : allProductOptions ) {          
            String current = po.getName();
            if ( current.equalsIgnoreCase("Shirt Color") ) {
                ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
                productOptionXref.setProductOption(po);
                productOptionXref.setProduct(product);
                productOptionXrefs.add(productOptionXref);
            }               
        }
    }

    product.setProductOptionXrefs(productOptionXrefs);

    Product finalProduct = catalogService.saveProduct(product);
    finalProduct.getDefaultSku().setDefaultProduct(finalProduct);
    catalogService.saveSku(finalProduct.getDefaultSku());        
    Long newId = finalProduct.getId();

    ProductWrapper response;
    response = (ProductWrapper) context.getBean(ProductWrapper.class.getName());
    response.wrapDetails(product, request);
    response.setId(newId);

    return response;
}

乔恩

【问题讨论】:

    标签: broadleaf-commerce


    【解决方案1】:

    看起来您所拥有的大部分内容都是正确的。但是,您缺少默认 Sku 的反向引用;诚然,这有点奇怪。这部分你说对了:

    Product product = catalogService.createProduct(ProductType.PRODUCT);
    product.setDefaultSku(defaultSku);
    

    但是您还需要确保默认 sku 引用回产品;你先保存产品然后设置它:

    ...
    Product finalProduct = catalogService.saveProduct(product);
    finalProduct.getDefaultSku().setDefaultProduct(finalProduct);
    catalogService.saveSku(finalProduct.getDefaultSku());
    

    上面的这段代码当前返回一个“Not-null”错误:

    你是对的,问题出在这段代码中,这是因为你没有在ProductOptionXrefImpl上设置product属性:

    if ( current.equalsIgnoreCase("Shirt Color") ) {
        ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
        productOptionXref.setProductOption(po);
        productOptionXrefs.add(productOptionXref);
    }
    

    如果您查看ProductOptionXrefImpl 中的product 属性,您会发现:

    @ManyToOne(targetEntity = ProductImpl.class, optional=false, cascade = CascadeType.REFRESH)
    @JoinColumn(name = "PRODUCT_ID")
    protected Product product = new ProductImpl();
    

    您正在超越optional=false 部分,但new ProductImpl() 部分使其始终是Hibernate 的“瞬态”实例;它没有 ID 属性,Hibernate 对此一无所知。由于cascade 仅设置为REFRESH,Hibernate 也不会尝试持久化它或任何东西(它不应该)。

    解决方法是在选项外部参照上设置product 属性:

    if ( current.equalsIgnoreCase("Shirt Color") ) {
        ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
        productOptionXref.setProductOption(po);
        productOptionXref.setProduct(product);
        productOptionXrefs.add(productOptionXref);
    }
    

    认为这会起作用,但您可能必须将产品选项创建移动到您第一次保存产品的下方,并将其设置为finalProduct。但我认为所有的级联都可以解决。

    【讨论】:

    • 是的,这行得通。我很欣赏快速响应和示例,以及花时间解释/教授解决方案背后的推理。我能够在几分钟内实施和测试。谢谢@phillipuniverse。
    猜你喜欢
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    相关资源
    最近更新 更多