簡體   English   中英

使用spring boot和hibernate強制執行外鍵約束的替代方法

[英]Alternative way to enforce foreign key constraint using spring boot and hibernate

有沒有其他方法可以使用JPA,Hibernate等強制執行外鍵約束,以最小化存儲在POJO中的數據?

我有一個Spring Boot項目,其中包含連接到MySQL數據庫的User和Form Model,Dao和Controller類。 用戶可以擁有多個表單,但表單只能有一個用戶。 所以關系是一對多的。 為了強制執行外鍵約束,我將@OneToMany注釋與List一起使用。 使用這種設計,當我在郵遞員中使用HTTP GET方法時,單個用戶返回用戶AND所有他/她關聯的表單,我不喜歡。 是否有另一種方法來強制執行外鍵約束,這樣我就不必存儲針對User類的所有信息,而是確保數據庫中的引用完整性?

以下是我的用戶類。 在底部是我創建Form類型的List並使用@OneToMany注釋對其進行注釋,然后使用@JoinColumn告訴它表單類中的哪個屬性加入它

package org.hoa.HOA_Website.WebsiteDatabaseAPI.Entities;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.List;


@Entity
@Table
public class User {

    @Id
    @GeneratedValue
    @Column(name = "user_id", insertable = false, updatable = false)
    private Long userID;

    @NotBlank
    @Column(length = 30, nullable = false)
    private String firstName;

    @NotBlank
    @Column(length = 30, nullable = false)
    private String lastName;

    @NotBlank
    @Column(length = 30)
    private String middleName;

    @NotBlank
    @Column(length = 14)
    private String phoneNumber;

    @NotBlank
    @Column(length = 50, unique = true, nullable = false)
    private String email;

    @Column(nullable = false)
    private Boolean admin;

    private int age;

    @NotBlank
    @Column(length = 100, nullable = false)
    private String passwordHash;

    @OneToMany(targetEntity = Form.class, cascade = CascadeType.ALL)
    @JoinColumn(name = "submitter_id")
    private List<Form> formsMade;
/*
Getters and Setters Below
*/

現在,這里是Form Class。 在提交者上面,我有一個名為“@JoinColumn”注釋的列。 這可確保通過POST方法發送的所有提交者ID具有匹配的用戶ID。

package org.hoa.HOA_Website.WebsiteDatabaseAPI.Entities;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table
public class Form {

    @Id
    @GeneratedValue
    private Long formID;

    @Column(nullable = false)
    private Date dateSubmitted;

    @Column(name = "submitter_id", nullable = false)
    private Long submitter;

    @Column(nullable = false)
    private Boolean approvalStatus;

    @Column(length = 30, nullable = false)
    private String formType;
/*
Getters and Setters Below
*/

但是,當我執行GET方法來查找所有用戶時。 我得到所有用戶及其相關表格。

[
    {
        "userID": 1,
        "firstName": "Jane",
        "lastName": "Doe",
        "middleName": "Halyard",
        "phoneNumber": "1234567890",
        "email": "janedoe@gmail.com",
        "admin": false,
        "age": 20,
        "passwordHash": "klsjfougalsdg2e98y54e982ajsdng924uierg",
        "formsMade": [
            {
                "formID": 5,
                "dateSubmitted": "2019-06-11T12:25:43.000+0000",
                "submitter": 1,
                "approvalStatus": false,
                "formType": "ConstructionForm"
            },
            {
                "formID": 6,
                "dateSubmitted": "2019-06-11T12:25:43.000+0000",
                "submitter": 1,
                "approvalStatus": false,
                "formType": "HardshipForm"
            }
        ]
    },
    {
        "userID": 2,
        "firstName": "John",
        "lastName": "Doe",
        "middleName": "Michael",
        "phoneNumber": "0987654321",
        "email": "johndoe@gmail.com",
        "admin": true,
        "age": 32,
        "passwordHash": "klsjfougalsdg2e98y5423bt49sdgajsdng924uierg",
        "formsMade": [
            {
                "formID": 3,
                "dateSubmitted": "2019-06-11T12:25:43.000+0000",
                "submitter": 2,
                "approvalStatus": false,
                "formType": "HardshipForm"
            }
        ]
    }
]

最后,無論如何確保參照完整性但是沒有在用戶上存儲太多? 希望更像是關系數據結構,只是將外鍵存儲在表單上?

我認為你所追求的是一個DTO

有沒有其他方法可以使用JPA,Hibernate等強制執行外鍵約束,以最小化存儲在POJO中的數據?

討論POJO有點不准確。 您的實體定義ORM ,那些應該按原樣定義。 您應該考慮返回的數據。 您的entiteis實際上並不存儲數據,但您使用所有數據填充它們並返回所有數據(如果您查詢並按原樣返回),因此也將它們用作DTO。

您似乎將Collection<User> (so entities)作為響應返回。

相反,你應該返回一個DTO集合 - 比如 - Collection<SimpleUserDTO> ,其中DTO可能是這樣的:

public class SimpleUserDTO {
    public Long userID;
    public String firstName;
    public String lastName;
    public String middleName;
    public String phoneNumber;
    public String email;
    public Boolean admin;
    public int age;
    public String passwordHash;
    // NOTE: no formsMade here!
}

因此,您的Controller方法應該調用Service方法,該方法返回從一些已經映射為DTO的Repository方法獲得的DTO集合,或者作為Service方法然后逐個映射為DTO的實體。

在您的Service方法中,您可以將實體值映射到DTO - 逐個字段或者可能使用類似ModelMapper的庫 - 但我認為最好的方法是您實現了一個Repository方法(使用ProjectionTuple查詢)來填充此DTO直接從查詢中,讓Service方法調用它。

畢竟這個非常丑陋但容易實現的方法只是循環用戶控制器並將formsMade設置為null但它最終是一個非常低效的解決方案,並且不會是一種靈活的方式來處理所有這些轉換的東西不同的結果等......

有很多東西需要詳細解釋,但我希望通過這些信息,您可以從SO或其他相關文檔中找到更多信息。

並且:當然,在將數據傳遞給Controller時,您需要從DTO映射回實體。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM