所以我有一个推广域,类如实体、服务、控制器等。
但是我在Entity类中有一个接口属性,并且根据POST时传递的参数,该实例将是保存在DB中的子类。但是我遇到了Hibernate在这方面的奇怪行为。如果我将该属性设为促销季节="easter促销"
-首先,在控制台中,将应用程序创建为Christmas促销季节,然后更新为Easter促销季节,我不知道为什么,如果我再举一个例子,让我们说:促销季节="no促销"
,同样的问题...
我在查询中得到了错误的结果,以查看我们基于PromotionSeason的促销活动,如果我在数据库中保存了EasterPromotion,它将在查询结果中重新链接ChristmasPromotion。为什么会出现此问题?您可以从下面的Hibernate控制台日志中看到。。。
促销实体:
@Entity
@org.hibernate.annotations.DynamicInsert
@org.hibernate.annotations.DynamicUpdate
@Access(AccessType.FIELD)
public class Promotion {
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE) //pre Insert values
private Long promotionId;
//Strategy Pattern, maybe State pattern was more suitable?
//check this -> https://stackoverflow.com/questions/51138344/hibernate-persisting-a-composition-interface-of-strategy-pattern
@Convert(converter = PromotionConverter.class)
@Column(name = "PROMOTION_SEASON", nullable = false)
private PromotionSeason promotionSeason;
public Promotion() {}
public Promotion(PromotionSeason promotionSeason)
{
this.promotionSeason = promotionSeason;
}
public Long getPromotionId() {
return promotionId;
}
public PromotionSeason getPromotionSeason() {
return promotionSeason;
}
public void setPromotionSeason(PromotionSeason promotionSeason) {
this.promotionSeason = promotionSeason;
}
}
促销服务
@Service
public class PromotionService {
private final PromotionRepository promotionRepository;
private final PromotionCallingOthers promotionCallingOthers;
@PersistenceContext
private EntityManager entityManager;
@Autowired
public PromotionService(PromotionRepository promotionRepository, PromotionCallingOthers promotionCallingOthers) {
this.promotionRepository = promotionRepository;
this.promotionCallingOthers = promotionCallingOthers;
}
public void createPromotion(Promotion promotion)
{
System.out.println(promotion.getPromotionSeason().isSeason());
this.promotionRepository.save(promotion);
}
public void addProducts(Promotion promotion, String productName) {
Promotion createdPromotion = new Promotion(promotion.getPromotionSeason());
ResponseEntity<Product> productResponseEntity = promotionCallingOthers.callProduct(productName);
Session session = entityManager.unwrap(Session.class);
session.update(productResponseEntity.getBody()); // for detached entity error
createdPromotion.addProduct(productResponseEntity.getBody());
double price = createdPromotion.getProductList().get(0).getProductPrice();
double discountedPrice = createdPromotion.getPromotionSeason().applySeasonPromotionDiscount(price);
double priceTo = getDigitsFormat(price - discountedPrice);
Objects.requireNonNull(productResponseEntity.getBody()).setProductPrice(priceTo);
createdPromotion.setNumberOfProductsAtPromotion(productResponseEntity.getBody().getProductQuantity());
this.promotionRepository.save(createdPromotion);
}
private double getDigitsFormat(double numberToFormat)
{
DecimalFormat formatDecimal = new DecimalFormat("#.##");
return Double.parseDouble(formatDecimal.format(numberToFormat));
}
public Promotion createPromotionWithType(String promotionType) {
Promotion promotion = new Promotion();
promotion.setPromotionSeason(setPromotionSeasonImplBasedOnType(promotionType));
promotionRepository.save(promotion);
return promotion;
}
public Promotion getPromotionSeasonBasedOnSomething(String promotionType)
{
PromotionSeason promotionSeason = setPromotionSeasonImplBasedOnType(promotionType);
Promotion promotion = promotionRepository.findPromotionByPromotionSeason(promotionSeason);
System.out.println(promotion.getPromotionSeason());
return promotion;
}
private PromotionSeason setPromotionSeasonImplBasedOnType(String promotionType)
{
// eh, state pattern would be better i guess
switch (promotionType.toLowerCase()) {
case "christmas":
return new PromotionChristmasSeason();
case "easter":
return new PromotionEasterSeason();
default:
return new NoPromotionForYouThisTimeMUHAHA();
}
}
public Promotion test(String testam) {
PromotionSeason promotionSeason = checkPromotionSeason(testam);
System.out.println(promotionSeason.isSeason());
Promotion promotion = promotionRepository.findWhatPromotionSeasonWeHave(promotionSeason);
if (promotion == null) {
System.out.println("promotion season ii in if: " + promotionSeason.isSeason());
Promotion promotion1 = new Promotion(promotionSeason);
System.out.println(promotion1.getPromotionSeason().isSeason());
//?
promotion = promotion1;
System.out.println(promotion.getPromotionSeason().isSeason());
promotion.setPromotionStore(promotion1.getPromotionStore());
promotionRepository.save(promotion);
System.out.println(promotion.getPromotionSeason().isSeason());
return promotion;
}
promotion.setPromotionSeason(promotionSeason);
promotionRepository.save(promotion);
System.out.println("promotion is" + promotion.getPromotionSeason().isSeason());
return promotion;
}
private PromotionSeason checkPromotionSeason(String promotionSeason)
{
System.out.println("is \n" + promotionSeason.toLowerCase());
switch (promotionSeason.toLowerCase().trim())
{
case "easter" :
return new PromotionEasterSeason();
case "christmas" :
return new PromotionChristmasSeason();
default:
return new NoPromotionForYouThisTimeMUHAHA();
}
}
促销资源库:
@Repository
public interface PromotionRepository extends JpaRepository<Promotion, Long> {
@Query("SELECT s FROM Promotion s WHERE s.promotionSeason = :promotionSeason")
Promotion findWhatPromotionSeasonWeHave(@Param("promotionSeason") PromotionSeason promotionSeason);
Promotion findPromotionByPromotionSeason(PromotionSeason promotionSeason);
}
促销控制器:
@RestController
@RequestMapping(value = "/promotions")
public class PromotionController {
private final PromotionService promotionService;
@Autowired
public PromotionController(PromotionService promotionService) {
this.promotionService = promotionService;
}
@PostMapping(value = "/createPromotion")
public ResponseEntity<String> createPromotion(@RequestBody Promotion promotion)
{
promotionService.createPromotion(promotion);
return ResponseEntity.status(HttpStatus.CREATED)
.body("Done");
}
@GetMapping(value = "/createPromotion/{promotionType}")
public ResponseEntity<Promotion> createPromotionType(@PathVariable String promotionType)
{
return ResponseEntity.status(HttpStatus.CREATED).body(promotionService.createPromotionWithType(promotionType));
}
//WRONG RESULT
@GetMapping(value = "/getPromotion/{promotionType}")
public ResponseEntity<Promotion> getPromotionType(@PathVariable String promotionType)
{
return ResponseEntity.status(HttpStatus.FOUND).body(promotionService.getPromotionSeasonBasedOnSomething(promotionType));
}
//WRONG RESULT
@GetMapping(value = "/test/{promotion}")
public Promotion check(@PathVariable String promotion)
{
return promotionService.test(promotion);
}
}
促销季节界面:
//see: -> https://www.youtube.com/watch?v=IlLC3Yetil0
//see: -> https://stackoverflow.com/questions/72155637/a-way-of-polymorphic-http-requests-using-postman/72158992#72158992
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "promotion")
@JsonSubTypes(
{ @JsonSubTypes.Type(value = PromotionEasterSeason.class, name = "easterPromotion"),
@JsonSubTypes.Type(value = PromotionChristmasSeason.class, name = "christmasPromotion"),
@JsonSubTypes.Type(value = NoPromotionForYouThisTimeMUHAHA.class, name = "noPromotion")
})
public interface PromotionSeason {
String isSeason();
double applySeasonPromotionDiscount(double initialPrice);
}
接口的Impl:
@JsonTypeName(value = "easterPromotion")
public class PromotionEasterSeason implements PromotionSeason{
private double promotionProcentToDiscount = 10.99f;
@Override
public String isSeason() {
return "Is Easter Season Discount Time of the Year again!";
}
@Override
public double applySeasonPromotionDiscount(double initialPrice) {
System.out.println("Now you have to pay less with: " + calculateDiscount(initialPrice) + ", instead of: " + initialPrice);
return calculateDiscount(initialPrice);
}
private double calculateDiscount(double initialPriceToDiscount)
{
return this.promotionProcentToDiscount / initialPriceToDiscount;
}
}
促销转换器类:
public class PromotionConverter implements AttributeConverter<PromotionSeason, String> {
@Override
public String convertToDatabaseColumn(PromotionSeason attribute) {
return attribute.getClass().getSimpleName().trim().toLowerCase(Locale.ROOT);
}
@Override
public PromotionSeason convertToEntityAttribute(@NotBlank String dbData) {
return stateOfPromotion(dbData);
}
private PromotionSeason stateOfPromotion(String state)
{
return state.equals("easterPromotion") ? new PromotionEasterSeason() : new PromotionChristmasSeason();
}
}
Hibernate SQL 控制台:
2022-08-07 12:16:37.123 DEBUG 7432 --- [nio-8080-exec-2] org.hibernate.SQL : call next value for hibernate_sequence
2022-08-07 12:16:37.249 DEBUG 7432 --- [nio-8080-exec-2] org.hibernate.SQL : insert into PROJECT_HIBERNATE_Promotion (NUMBER_PRODUCTS_AT_PROMOTION, PROMOTION_SEASON, promotionId) values (?, ?, ?)
2022-08-07 12:16:37.258 TRACE 7432 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [0]
2022-08-07 12:16:37.260 DEBUG 7432 --- [nio-8080-exec-2] tributeConverterSqlTypeDescriptorAdapter : Converted value on binding : com.shoppingprojectwithhibernate.PromotionsModule.Domain.PromotionChristmasSeason@54de6f66 -> promotionchristmasseason
2022-08-07 12:16:37.260 TRACE 7432 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [promotionchristmasseason]
2022-08-07 12:16:37.261 TRACE 7432 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [BIGINT] - [1]
2022-08-07 12:16:37.271 DEBUG 7432 --- [nio-8080-exec-2] org.hibernate.SQL : update PROJECT_HIBERNATE_Promotion set PROMOTION_SEASON=? where promotionId=?
2022-08-07 12:16:37.273 DEBUG 7432 --- [nio-8080-exec-2] tributeConverterSqlTypeDescriptorAdapter : Converted value on binding : com.shoppingprojectwithhibernate.PromotionsModule.Domain.PromotionEasterSeason@18c401ef -> promotioneasterseason
2022-08-07 12:16:37.274 TRACE 7432 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [promotioneasterseason]
2022-08-07 12:16:37.275 TRACE 7432 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [BIGINT] - [1]
类PromotionConverter
中的方法执行的操作不一致:
convertToDatabaseColumn
将转换为促销季节类的小写名称,因此它将返回:promotioneasterseason
orpromotionchristmasseason
或NoPromotionForYouthistimumuHaha
。这是将存储在数据库中的字符串。
但是方法<code>convertToEntityAttribute</code>应该做相反的事情,它还做了其他事情:如果数据库中的字符串是<code>easterPromotion</code>那么它将返回<code>PromotionEasterSeason</code>类型的对象,否则将返回<code>Promotion ChristmasSeason>/code>类型的对象。
那么,当您在数据库中保存复活节促销时会发生什么:Hibernate将存储字符串促销EasterSeason
。当您从数据中读取该记录时,转换器注意到该记录与easterPromotion
不匹配,因此它将返回促销Christmasseason
。
解决方案:确保方法convertToDatabaseColumn
和convertToEntityAttribute
。
当我保存以下实体时,它在另一个对象中复制相同的值: 例如,在我的struts项目(屏幕)中,如果我更改shipmentShipper字段的值,那么Shipment收货人也将使用相同的值进行更新。 实体: 仓库类: JSP中的字段映射(工作正常): 请检查屏幕截图,我将发货人更改为C4并保存。收货人也被选为C4。请注意,两个选择都使用相同的数据列表填充。(客户名单)
问题内容: 如何保存hibernate实体并忽略(不正确)瞬态模式。 例如: 我想保存它: 弹簧产生错误: 问题答案: 参见http://docs.jboss.org/hibernate/validator/4.2/reference/en- US/html_single/#validator-checkconstraints- orm 。默认情况下,Hibernate(ORM)检查默认验证组的每
问题内容: 我在父方使用批注具有一对一关系。现在,我想自己保存子实体。 例如,我有和作为孩子的实体,我需要保存(父的id属性设置为之后的课程)。但是,当使用这种安排时,我在下面列出了一个例外… 为什么hibernate不允许这样做的任何想法?更清楚地说,我的代码如下… ParentEntity: ChildEntity: 我尝试保存的方式是… 关于如何尝试保存子实体,任何指针将不胜感激。 问题答案
我正在使用Mapstruct映射将一个POJO转换为另一个POJO模型 以下是mapstruct自动生成的方法 该方法基本上获取源POJO的映射,并将其转换为目标模型的映射。生成正在通过。 当我运行代码时,我在这个方法中得到了ClassCast异常:HeaderAttributeGenericDataTypeMaptoStringEnergiectAttributeDataMap 堆栈跟踪: 我还
我是Hibernate的新手,并要求使用具有这些列的表的数据库 表:TBL _ product//库存项目列表< br >列:< br > key _ product < br > key _ category < br > fld _ product _ name < br > fld _ Inventory _ qty < br > fld _ unit _ price < br > fld
为了方便起见,我想创建datetime的子类。时间三角洲。这样做的目的是定义一个类: 所以我可以快速创建这样的时间增量: 然而,上面的代码产生了n天而不是n小时的时间增量。例如,请看以下ipython会话: 我无法解释这一点。有人吗?