【问题标题】:Is using id field in @AllArgsConstructor while using Spring JPA correct?使用 Spring JPA 时在 @AllArgsConstructor 中使用 id 字段是否正确?
【发布时间】:2018-07-24 21:25:15
【问题描述】:

使用spring-boot 和JPA 我有一个Entity 我想使用lombok 来减少样板代码。但是在我的实体中有id 字段。我应该把它放在带有@AllArgsConstructor 的构造函数参数中,还是应该从参数列表中删除它(不知何故,如何?)由于使用@id@GeneratedValue 注释自动生成?

代码:

@Entity
@NoArgsConstructor // JPA requires empty constructor
@AllArgsConstructor // ? is id in constuctor needed?

@Getter
@Setter
@ToString(exclude = {"room", "customer"})
public class Reservation {

    @Id
    @GeneratedValue
    private long id;

    private Room room;
    private Customer customer;
    private Date dateFrom;
    private Date dateTo;    
}

【问题讨论】:

    标签: java spring spring-boot jpa lombok


    【解决方案1】:

    关于代码中的问题:

    @AllArgsConstructor // ?需要构造函数中的 id 吗?

    不,不需要。此外,对于您在标题中的问题:

    在使用 Spring JPA 时在 @AllArgsConstructor 中使用 id 字段是否正确?

    字段id 除非有充分的理由,否则不建议将其暴露给任何构造函数或设置器。字段 id 只能由 JPA 实现操作。

    请注意,当您在 Reservation 类级别上声明 @Setter 时,也会发生这种公开。

    这可以避免从类级别删除注释并注释每个字段以公开,但更简单的方法是使用继承。

    你可以像这样创建一个基类:

    @Entity
    @Getter
    // Choose your inheritance strategy:
    //@Inheritance(strategy=InheritanceType.JOINED)
    //@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
    public abstract class BaseEntity {
        @Id
        @GeneratedValue
        private Long id;
    }
    

    请注意,它没有字段 id 的设置器。扩展上面的类,如:

    @Entity
    @NoArgsConstructor
    @AllArgsConstructor
    @Getter
    @Setter
    @ToString(exclude = {"room", "customer"})
    public class Reservation extends BaseEntity {
        private Room room;
        private Customer customer;
        private Date dateFrom;
        private Date dateTo;    
    }
    

    构造器和设置器如下:

    Reservation r1 = new Reservation();
    Reservation r2 = new Reservation(room, customer, dateFrom, dateTo);
    
    r1.setRoom(room);
    r1.setCustomer(customer);
    r1.setDateFrom(dateFrom);
    r1.setDateTo(dateTo);
    

    除了 JPA 使用的反射之外,没有其他方法可以设置字段 id

    我不知道 究竟是如何设置id 但由于有一个关键字JPA 和标签 我认为这是一个JPA 的事情并且字段id 的设置器实际上并不需要全部。

    【讨论】:

    • @pirhhp 我可以仅将@MappedSuperclass 用于BaseEntity 而不是@Entity @Getter@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) 吗?将Reservation 保留在您的代码中?
    • 是的。实际上,虽然BaseEntity 是抽象的,但如果出于其他原因不需要,您甚至可以将@MappedSuperclass 排除在外。但是你真的想摆脱 id 的 getter 吗?
    • 但如果没有@MappedSuperclass,它会在db的子类实体中包含id,而只留下@Getter@MappedSuperclass @Getter是必需的吗?
    • 我正在使用 OpenJPA,不管有没有,它都能很好地工作。但是,将@MappedSuperclass 排除在外会禁用在继承类中使用@AttributeOverride 的示例。但id 会按原样生成。
    【解决方案2】:

    Lombok 部分的注释:无法从@AllArgsConstructor 中排除字段(不使用继承)。对于有限的构造函数,您只能使用@RequiredArgsConstructor,但这通常对 JPA 实体没有帮助。

    【讨论】:

    • 是的。关于这个细节是另一个question
    【解决方案3】:

    在这种情况下,spring-data 使用 setter 来设置值,因此不需要 @AllArgsConstructor

    【讨论】:

    • 在这种情况下,@AllArgsConstructor 实际上是有害的。 @Id 不应写入客户端代码中。请参阅@pirho 的答案以获得解释。
    猜你喜欢
    • 2021-08-02
    • 1970-01-01
    • 2018-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 2020-02-09
    相关资源
    最近更新 更多