【问题标题】:JPA Hibernate Split data between two tablesJPA Hibernate 在两个表之间拆分数据
【发布时间】:2019-04-11 02:52:51
【问题描述】:

我有一个 REST API,它将接收以下格式的一些客户数据:

{
    "customer_Id": 50,
    "name": "name",
    "company_name": "company_name",
    "email": "email@provider.com",
    "business_phone": "(00) 1111-2222",
    "mobile_phone": "(00) 1111-2222",
    "document": "123456789",
    "state_registration_number": "ISENTO",
    "state_registration_type": "NO_CONTRIBUTOR",
    "city_registration_number": "ISENTO",
    "classification": "AUTO",
    "address": {
        "street": "STREET NAME XXX",
        "number": "NUMBER XX",
        "complement": "COMPLEMENT",
        "zip_code": "ZIP_CODE",
        "neighborhood": "NEIGHBORHOOD",
        "city": "CITY",
        "state": "STATE"
    }
}

我想将此数据保存在两张表中:一张表应包含“主要”客户数据,另一张表应包含客户的“地址”数据。

所以,我将Customer 实体定义如下:

@Data
@Entity(name = "X_CUSTOMERS")
public class Customer {

    @Id
    private int customer_Id;

    @NotNull
    private String name;

    private String company_name;

    private String email;

    private String business_phone;

    private String mobile_phone;

    @NotNull
    private String document;

    private String state_registration_number;

    private String state_registration_type;

    private String city_registration_number;

    @NotNull
    private String classification;

    @OneToOne(cascade = CascadeType.ALL)
    private Address address;

}

而Address 实体为

@Data
@Entity(name = "X_ADDRESS")
public class Address {

    @NotNull
    private String street;

    private String number;

    private String complement;

    private String zip_code;

    private String neighborhood;

    private String city;

    private String state;

}

但是,我不知道如何在它们之间建立关系。我应该在Address 实体上创建customer_id 属性吗?我应该在Customer 的address 属性上定义一些额外的标签吗?请注意,我在 REST 客户端发布的 JSON 数据上没有客户,如果客户更新或删除,地址数据也应该更新/删除。

抱歉,这是一个如此琐碎的问题。这些天我正在学习 JPA/Hibernate 的基础知识,您的回答将引导我走向正确的方向,以避免“重新发明轮子”之类的事情。

非常感谢!

【问题讨论】:

    标签: spring hibernate spring-boot jpa


    【解决方案1】:

    如果我们认为地址是一个值对象而不是实体,那么它可以映射如下。在您的情况下,将其建模为 VO 可能是正确的:如果您正在构建地址数据库,那么它可以被视为一个实体。在此处进一步查看:

    Value vs Entity objects (Domain Driven Design)

    然后我们可以将地址类设为@Embeddable 而不是实体:这样它就不会有任何自己的身份。要将客户和地址详细信息存储在单独的表中,我们还可以使用 JPA @SecondaryTable 功能:

    https://docs.oracle.com/javaee/7/api/javax/persistence/SecondaryTable.html

    然后我们有如下模型类。使用这些映射,您的 JSON 更新将按预期工作。

    客户:

    @Data
    @Table(name = "customers")
    @SecondaryTable(name = "customer_addresses",  pkJoinColumns={
            @PrimaryKeyJoinColumn(name="customer_id", 
                referencedColumnName="customer_id")})
    public class Customer {
    
        protected static final String ADDRESS_TABLE_NAME = "customer_addresses";
    
        // other fields
    
        @Embedded
        private Address address;
    
    }
    

    地址:

    @Data
    @Embeddable
    public class Address {
    
        @NotNull
        @Column(table = Customer.ADDRESS_TABLE_NAME)
        private String street;
    
        @Column(table = Customer.ADDRESS_TABLE_NAME)
        private String number;
    
        @Column(table = Customer.ADDRESS_TABLE_NAME)
        private String complement;
    
        @Column(table = Customer.ADDRESS_TABLE_NAME)
        private String zip_code;
    
        @Column(table = Customer.ADDRESS_TABLE_NAME)
        private String neighborhood;
    
        @Column(table = Customer.ADDRESS_TABLE_NAME)
        private String city;
    
        @Column(table = Customer.ADDRESS_TABLE_NAME)
        private String state;
    }
    

    【讨论】:

    • 发挥了魅力!非常感谢@Alan!
    【解决方案2】:

    这就是我的做法:

    @OneToOne (fetch=FetchType.EAGER, cascade = CascadeType.ALL, optional = false)
    @NotNull(message = "L'addresse du domicile est requise!", groups = Seventh.class)
    @Getter
    @Setter
    private Address homeAddress;
    

    不需要任何逆映射,这让我可以一举保存客户及其地址!

    您还需要一个地址实体的 ID,例如:

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(unique = true, nullable = false)
    @Getter
    @Setter
    private Long id;
    

    【讨论】:

    • 更改地址映射属性不起作用。 JPA 无法创建表并出现以下错误:No identifier specified for entity: br.com.customers.entity.Address。如果我在Address 实体上添加customer_id 属性,并使用标签@Id 进行注释,则会创建表,但Address.customer_id 始终设置为0,而不是传递给控制器​​的正确值...
    • Martin,这样我们将始终为每个地址获取一个新 ID。这不是我需要的。 Address 表的主键也应该是 customer_id ...
    • 你到底为什么有这个要求?
    • 我需要在特定表上填充地址数据,而不是拥有一个包含大量列的唯一表...
    • 具有与您的 customer_id 不同的 id 仍会达到此结果。我不相信您的地址可以与您的客户具有相同的 ID,我也不相信有任何理由期望这是诚实的。按照我的建议进行操作确实将客户/地址数据拆分为 2 个表,并允许您直接从客户实体访问地址数据。一个实体需要一个 id 才能让休眠甚至创建表,但在这种情况下,address_id 真的无关紧要,因为每个客户实体都会引用它并且能够访问它的所有成员。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多