【问题标题】:How should I map these 2 simple entities in JPA?我应该如何在 JPA 中映射这两个简单的实体?
【发布时间】:2013-09-11 14:46:29
【问题描述】:

我目前拥有的:

@Entity
public class Payment {

    @Id @GeneratedValue
    private long id;

    @Column(unique = true)
    private Date period; // Only used for year and month

    ...
}

@Entity
public class Department {

    @Id @GeneratedValue
    private long id;

    ...
}

支付实体只保存需要由所有部门每年和每月支付一次的默认付款。他们之间不需要任何关系,因为所有部门都支付所有款项。

我想要达到的目标:

我想区分当前共享的付款和其他一些部门特定的付款。因此,部门将能够选择使用所有共享付款(按照目前的设计)或定义自己的付款而不使用任何其他付款。

公司付款应继续以相同的方式工作,我必须确保每个部门的部门付款也是唯一的。

在 OOP 术语中,我认为我需要对以下任何选项进行建模:

可能第一个更合适。

请注意,我无法更改当前识别任何实体的方式。但是,我可以在任何其他字段上添加唯一性。

问题:

  1. 在 JPA2 中执行此操作的适当方法是什么?
  2. 付款层次结构是否可行?应该如何映射以确保唯一 字段不冲突?
  3. 有什么办法可以避免层次结构吗?

【问题讨论】:

  • 扩展层次结构选项:这将是一个带有鉴别器 (C|D) 的表,它将同时具有 CompanyPayments 和 DepartmentPayments,因此唯一性将由这对确定:鉴别器列和周期列跨度>

标签: java hibernate jpa mapping jpa-2.0


【解决方案1】:

我认为这个场景确实需要关系:

@Entity
public class Payment {

    @Id @GeneratedValue
    private long id;

    @Column(unique = true)
    private Date period; // Only used for year and month

    @ManyToOne
    private Department department;
}

这将允许为任何部门创建任何类型的付款。至于部门的默认付款,我认为这超出了 ORM 的责任范围,应该在业务逻辑中处理。

【讨论】:

  • 我相信关系确实是必须的。但这还不够。这不会处理唯一的部门|期间对。没有部门的付款被视为默认付款。与数据库术语一样,您有一个 Payment 表,其中包含可以为空的 Departments 的 FK。如果 FK 为空,则付款为默认值。因此,在 PaymentId 和 FKDepartmentID 上设置一个复合唯一索引(不是 PK!)就可以了。我认为在 JPA 中一定有某种方法可以做到这一点。
【解决方案2】:

如果我理解正确,您需要实现每个部门的唯一性。可以使用compound id。 几点:

  • 如果你想使用复合键(period+department_id),你必须同时设置它们,并且你的默认付款应该有1 common fake Department,所有默认的payments都属于。
  • 一般情况下我会关注Kevin's approach。这很容易且不易出错。反正你决定。

@Entity
public class Payment implements Serializable {

    @EmbeddedId
    private Period period;
}

@Embeddable
public class Period implements Serializable {
    @ManyToOne
    private Department department;
    private Date period;
}


@Entity
public class Department implements Serializable {
    @Id@GeneratedValue
    private long id;

    @OneToMany
    private List<Payment> payments = new ArrayList<Payment>();
}

【讨论】:

  • 我实际上无法更改当前付款的 ID。正如我在凯文的回答中的评论中提到的,我不能使用复合 PK,但我可以使用唯一索引。另外,我不喜欢假部门的想法(这是因为你有一个复合 PK 而不是一个复合唯一索引)。现在,正如我在问题的评论中提到的那样,为了解决这个问题,可以将层次结构与两种类型的部门的鉴别器一起使用,对吧?我是否有可能保留当前存在的简单 PK 并保持与 discriminator 和 department_FK 对的唯一性?
  • 我将赏金奖励给你,作为第二个最佳答案,IMO。
【解决方案3】:

我无法将 PK 保存在我的 Payment 实体中,也无法在 Period 和 Department 上维护一个唯一索引。在数据库方面,我正在寻找这些:

付款(ID、期间、FK_Department)

并且该表应该在 Period 和 FK_Department 中添加一个唯一索引,这将允许在 FK_Department 中使用空值(因为您可以看到复合 PK 不是一个选项,因为我需要保持使用相同的 PK 结构) .使用该表,所有 FK_Department 值为空的付款将是通用/默认/公司付款,而具有非空 FK_Department 的付款将是特定部门分配的付款,因此它将使用这些而不是公司付款。

由于我对 JPA 缺乏了解,我无法复制此架构。但是,我可以创建一个类似的功能模式。这是迄今为止我想出的最好的:

由于其明显糟糕的期间重复,我可以设法为每个表创建两个唯一索引:一个用于 CompanyPayment 实体的 Period ,一个用于 DepartmentPayment 实体的 Period 和 Department 对:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Payment {

    @Id @GeneratedValue
    private long id;

    ...
}

@Entity
public class CompanyPayment extends Payment {

    @Column(unique = true)  
    public Date period;

    ...
}

@Entity
@Table(uniqueConstraints =
    @UniqueConstraint(columnNames = { "period", "department_id" })
)
public class DepartmentPayment extends Payment {

    public Date period;

    @ManyToOne(optional = false)
    @JoinColumn(name = "department_id")
    private Department department;

    ...
}

我现在将使用此解决方案,但我愿意接受任何其他更好的解决方案。

【讨论】:

    猜你喜欢
    • 2015-10-03
    • 2021-10-16
    • 2011-07-13
    • 2011-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 2021-09-13
    相关资源
    最近更新 更多