Broadleaf 5.2 - 如何通过 API 将 ProductOptions 设置到新创建的产品中?
Broadleaf 5.2 - How do I set ProductOptions into a newly created Product via the API?
问题:
我看到产品“setProductOptions()”方法已被弃用,“setProductOptionXrefs()”方法已被弃用首选。问题是我似乎找不到任何有关如何设置 ProductOptionXrefs 的示例。
我在 Broadleaf“BroadleafCommerce-develop-5.2.x”和“DemoSite-broadleaf-5.2”中寻找示例。 2.1-GA”项目以及梳理星系为例。运气不好。
目标 (X):
我正在创建一个端点,它将接受一个 JSON 对象并接受两个参数,(categoryName 和 price ).
端点将:
- 找到产品所属的类别。
- 创建一个新的 Sku 对象并填充一些输入 wrapper 字段。
- 创建一个新的 Product 对象并填充几个 wrapper 字段。
- 为这个新产品分配一个 ProductOption。 <== X
- 保存产品。
- Return 一个响应(对于 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 为 "Merchandise",价格 为 19.00。
以上代码当前返回 "Not-null" 错误:
Not-null property references a transient value - transient instance
must be saved before current operation:
org.broadleafcommerce.core.catalog.domain.ProductOptionXrefImpl.product
-> org.broadleafcommerce.core.catalog.domain.ProductImpl; nested exception is java.lang.IllegalStateException:
org.hibernate.TransientPropertyValueException: Not-null property
references a transient value - transient instance must be saved before
current operation:
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);
}
and/or
Product finalProduct = catalogService.saveProduct(product);
上面几行。
我可以(最终)找出 "Not-null" 错误,但我问的问题是,是否有人有将 ProductOption 或 ProductOptionXref 添加到新创建的产品的示例?
谢谢
乔恩
[更新]
我想用解决方案更新我的问题,非常感谢@phillipuniverse example/explanations。
@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;
}
乔恩
看起来你所拥有的大部分内容都是正确的。不过,您缺少默认 Sku 的反向引用;诚然,这有点奇怪。你做对了这部分:
Product product = catalogService.createProduct(ProductType.PRODUCT);
product.setDefaultSku(defaultSku);
但是您还需要确保默认 sku 引用回产品;你有先保存产品然后设置它:
...
Product finalProduct = catalogService.saveProduct(product);
finalProduct.getDefaultSku().setDefaultProduct(finalProduct);
catalogService.saveSku(finalProduct.getDefaultSku());
This code above is currently returning a "Not-null" error:
你是对的,问题出在这段代码中,这是因为你没有在 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 的 'transient' 实例;它没有 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
。但我认为所有的级联都会解决这个问题。
问题:
我看到产品“setProductOptions()”方法已被弃用,“setProductOptionXrefs()”方法已被弃用首选。问题是我似乎找不到任何有关如何设置 ProductOptionXrefs 的示例。
我在 Broadleaf“BroadleafCommerce-develop-5.2.x”和“DemoSite-broadleaf-5.2”中寻找示例。 2.1-GA”项目以及梳理星系为例。运气不好。
目标 (X):
我正在创建一个端点,它将接受一个 JSON 对象并接受两个参数,(categoryName 和 price ).
端点将:
- 找到产品所属的类别。
- 创建一个新的 Sku 对象并填充一些输入 wrapper 字段。
- 创建一个新的 Product 对象并填充几个 wrapper 字段。
- 为这个新产品分配一个 ProductOption。 <== X
- 保存产品。
- Return 一个响应(对于 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 为 "Merchandise",价格 为 19.00。
以上代码当前返回 "Not-null" 错误:
Not-null property references a transient value - transient instance must be saved before current operation: org.broadleafcommerce.core.catalog.domain.ProductOptionXrefImpl.product -> org.broadleafcommerce.core.catalog.domain.ProductImpl; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: 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);
}
and/or
Product finalProduct = catalogService.saveProduct(product);
上面几行。
我可以(最终)找出 "Not-null" 错误,但我问的问题是,是否有人有将 ProductOption 或 ProductOptionXref 添加到新创建的产品的示例?
谢谢
乔恩
[更新]
我想用解决方案更新我的问题,非常感谢@phillipuniverse example/explanations。
@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;
}
乔恩
看起来你所拥有的大部分内容都是正确的。不过,您缺少默认 Sku 的反向引用;诚然,这有点奇怪。你做对了这部分:
Product product = catalogService.createProduct(ProductType.PRODUCT);
product.setDefaultSku(defaultSku);
但是您还需要确保默认 sku 引用回产品;你有先保存产品然后设置它:
...
Product finalProduct = catalogService.saveProduct(product);
finalProduct.getDefaultSku().setDefaultProduct(finalProduct);
catalogService.saveSku(finalProduct.getDefaultSku());
This code above is currently returning a "Not-null" error:
你是对的,问题出在这段代码中,这是因为你没有在 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 的 'transient' 实例;它没有 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
。但我认为所有的级联都会解决这个问题。