【问题标题】:JPA Entity Relationship for referencing the value but not updating the referenced entity用于引用值但不更新引用实体的 JPA 实体关系
【发布时间】:2016-07-09 16:51:50
【问题描述】:

有两个实体,
1.状态(两列:statusId状态)
例如值:1 ACTIVE、2 INACTIVE 等)
2.优惠券(三栏:couponId title statusId)
例如值:10 个橙子 1、20 个苹果 2 等)

试图弄清楚要使用什么关系以及如何使用。我尝试过 OneToOne、OneToMany、ManyToOne、ManyToMany 等,但每次状态实体都会添加一个新行
例如21 活跃,22 活跃,23 活跃,等等。

每次保存新优惠券时,Coupon 实体都应获取一个新行,并在 status id 字段中使用 status 的主键,但应添加一个新行。

Yes, Many coupons can share the same status.
The following code produces the following results

Before execution

Status Table
StatusId    STATUS
1           ACTIVE
2           INACTIVE

Coupon Table
CouponId    Title   STATUS
<no rows at present>


After execution

Status Table
StatusId    STATUS
1           ACTIVE
2           INACTIVE
3           ACTIVE  (This row should not get inserted)

Coupon Table
CouponId        Title   StatusId
10          Apples  3     (StatusId should be 1 instead of 3)




JSON Request: 

{
  "title": "Apples",
  "status": "ACTIVE",
}

Code:

@Autowired
CouponRespository couponRepository;

@RequestMapping(value = "/coupon", method = RequestMethod.POST)
void createCoupon(@RequestBody Coupon coupon) {
        couponRepository.save(coupon);
}

public interface CouponRespository extends JpaRepository<Coupon, Long> {

}

@Entity 
public class Status implements Serializable {

    @Id
    @SequenceGenerator(name = "STATUS_STATUSID_GENERATOR", sequenceName = "STATUS_ID_SEQ")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "STATUS_STATUSID_GENERATOR")
    @Column(name = "STATUS_ID")
    private long statusId;

    @Column(name = "STATUS")
    private String status;   
}


@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,    property = "couponId")
@JsonIgnoreProperties({ "statusId" }) 
public class Coupon implements Serializable {

    @Id
    @SequenceGenerator(name = "COUPON_COUPONID_GENERATOR", sequenceName = "COUPON_ID_SEQ")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "COUPON_COUPONID_GENERATOR")
    @Column(name = "COUPON_ID")
    private long couponId;

    @Column(name = "TITLE")
    private String title;

    @Column(name = "STATUS_ID")
    private Long statusId;

    // Need help here how to set this up properly
    @ManyToOne(cascade = { CascadeType.ALL })
    @JoinColumn(name = "STATUS_ID", insertable = false, updatable = false)
    private Status status;

}

感谢任何帮助。

【问题讨论】:

  • 那么,多张优惠券可以共享相同的状态吗?如果是,则为多对一,否则为一对一。发布您用于创建和保存优惠券的代码,说明您希望它做什么以及它会做什么。
  • @JBNizet 添加了代码以及数据库中的预期内容和更新内容

标签: jpa mapping


【解决方案1】:

我不知道杰克逊如何可能创建一个包含来自您问题中的 JSON 的状态实例的 Coupon 实例,更不用说新行如何出现在数据库中,因为 COupon 的状态字段不可插入,但是无论如何,假设它相当于以下内容:

Coupon coupon = new Coupon();
coupon.setTitle("Apples");
Status status = new Status("ACTIVE");
coupon.setStatus(status);

您要求将该优惠券保存到 JPA。你告诉 JPA 将持久化操作级联到优惠券中包含的状态。该状态没有任何 ID。那么除了创建一个新的 JPA 还能做什么呢?它怎么会猜到你真正想要的是将新的优惠券与 ID 1 标识的现有状态相关联?它不能。它做你告诉它做的事情。

那么,你应该怎么做呢?

首先,从 Coupon 中删除 statusId 字段。这是状态的ID,而你在优惠券中有状态,所以这个信息是多余的。

其次,您希望将优惠券与现有状态相关联。因此,获取此现有状态的引用,并在保存优惠券之前将其设置在优惠券中:

// this should execute a query that retrieves the Status entity 
// that has the "ACTIVE" status
Status status = statusRepository.findStatusByStatus("ACTIVE");

coupon.setStatus(status);
couponRepository.save(coupon);

第三:由于您不希望数据库中的两个状态具有相同的状态,因此向表添加唯一约束。

第四:由于您在保存或修改或删除引用此状态的优惠券时不想保存或修改或删除状态,请删除cascade = { CascadeType.ALL }。

第五:由于您希望对 coupon.status 的更改保持不变,请删除 insertable = false, updatable = false。

第六:因为您在控制器中以 JSON 形式接收的内容没有优惠券的结构,并且不是优惠券实例,而是标题和状态文本,允许您使用该文本找到状态并创建Coupon 实例,创建一个类 CouponCommandDTO,它的结构与您的 JSON 相同,并将其作为控制器参数的类型。然后使用上面显示的代码将此 DTO 转换为实际的 Coupon。

【讨论】:

  • 感谢您的回复。除了基本问题外,还有一些我不清楚的其他问题,但您的详细解释回答了我所有的问题。我尝试了您提到的解决方案并且它有效。我唯一没有做的是创建 CouponCommandDTO,而是将 status_id 设置为瞬态并使用该值来获取状态对象。再次感谢。它不仅解决了问题,而且消除了许多其他困扰我的疑虑。
猜你喜欢
  • 2012-10-02
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 2019-02-09
  • 2019-10-01
  • 1970-01-01
  • 2013-04-03
相关资源
最近更新 更多