简体   繁体   English

OneToMany 返回 null 响应来自目标实体的 JoinColumn,即使值已插入数据库 - Spring 启动 JPA

[英]OneToMany returns null in response on JoinColumn from target Entity even though value was inserted in database - Spring boot JPA

I have two Models/Entities that are combined with @OneToMany, saving PK from one table to other as Foreign key.我有两个与@OneToMany 结合的模型/实体,将 PK 从一个表保存到另一个表作为外键。 I want to get that newly updated foreign key in response aswell.我也想获得新更新的外键作为响应。

This is my code这是我的代码

CategoryModel类别型号

@Data
@AllArgsConstructor
@Getter
@Builder
public class CategoryModel {
    
    public String categoryName;
    public List<BeveragesModel> beverages;
    
}

BeveragesModel饮料模型

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BeveragesModel {
    
    public Integer categoryID;
    public String name;
    public double price;
    
    
}

Entities of the models currently have the same fields as models模型的实体当前具有与模型相同的字段

BeveragesEntity饮料实体

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "BEVERAGES")
@ToString
@Builder
public class BeveragesEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    public Integer id;
    @Column(name = "CATEGORY_ID")
    public Integer categoryId;
    @Column(name = "NAME")
    public String name;
    @Column(name = "PRICE")
    public double price;
    
    @ManyToOne
    public void setCategoryId(Integer id) {
        this.categoryId=id;
    }
    
}

CategoryEntity类别实体

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "CATEGORY")
public class CategoryEntity {

    // TO DO kako dobiti na front zapis iz BEVERAGES tablice za CATEGORY_ID kojeg spremam...
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    public Integer id;
    @Column(name = "CATEGORY_NAME")
    public String categoryName;
    @Column(name = "BEVERAGES")
    @OneToMany(targetEntity = BeveragesEntity.class, cascade = CascadeType.ALL)
    @JoinColumn(name = "CATEGORY_ID", referencedColumnName = "id")
    List<BeveragesEntity> beverages;
}

Controller is only calling service Controller 只是调用服务

@RestController
@CrossOrigin(origins = "*")
public class CategoryController {

    
    @Autowired
    CategoryService categoryService;

    @RequestMapping(path = "/addCategory", method = RequestMethod.PUT)
    public CategoryEntity addCategory(@RequestBody CategoryRequest request) {
        return categoryService.addCategory(request);
    }
    
}

CategoryService is currently rebuilding objects from models to entities CategoryService 目前正在将对象从模型重建为实体

@Service
public class CategoryServiceImpl implements CategoryService {
    
    @Autowired
    CategoryRepository categoryRepository;
    
    public CategoryEntity addCategory(CategoryRequest request) {
        
        List<BeveragesModel> beveragesModel = request.getCategory().getBeverages();
        List<BeveragesEntity> beveragesEnties = new ArrayList<>();
        if(!beveragesModel.isEmpty()) {
            for(BeveragesModel model : beveragesModel)  {
                BeveragesEntity beveragesEntity = BeveragesEntity.builder()
                        .name(model.getName())
                        .price(model.getPrice())
                        .build();
                beveragesEnties.add(beveragesEntity);
                
            }
        }
        
        CategoryEntity categoryEntity = CategoryEntity.builder()
                .categoryName(request.getCategory().getCategoryName())
                .beverages(beveragesEnties)
                .build();
        
        return categoryRepository.save(categoryEntity);
    }

Request is请求是

    { 
    "category" : {
        "categoryName": "Alkoholna pića",
        "beverages": [
            {
                "name":"Ozujsko",
                "price":16.0
            },
            {
                "name":"Stella Artois",
                "price":18.0
            }
        ]
    }
}

And this is response这是回应

    {
    "id": 1,
    "categoryName": "Alkoholna pića",
    "beverages": [
        {
            "id": 1,
            "categoryId": null,
            "name": "Ozujsko",
            "price": 16.0
        },
        {
            "id": 2,
            "categoryId": null,
            "name": "Stella Artois",
            "price": 18.0
        }
    ]
}

I want to get categoryId from objeck beverages in response from backend, but in response I get null.我想从 objeck 饮料中获取 categoryId 作为后端的响应,但作为响应我得到 null。 Howerver in my H2 database in BEVERAGES table I can see that categoryId is correctly saved with the ID from CATEGORY table (in this case both of this records have CATEGORY_ID = 1) Howerver 在我的 H2 数据库中的 BEVERAGES 表中,我可以看到 categoryId 与 CATEGORY 表中的 ID 正确保存(在这种情况下,这两条记录的 CATEGORY_ID = 1)

Would be greatfull if some one would help me out...如果有人能帮助我,那就太好了...

Your issue stems from BeverageEntity having a categoryId rather than a CategoryEntity.您的问题源于 BeverageEntity 具有 categoryId 而不是 CategoryEntity。 Normal bidirectional relationship would be as follows:正常的双向关系如下:

    // CategoryEntity
    @OneToMany(cascade = CascadeType.ALL)
    List<BeveragesEntity> beverages;

    // BeverageEntity
    @ManyToOne
    @JoinColumn(name = "CATEGORY_ID")
    private CategoryEntity category;

Before saving, as well as setting beverages collection into category you should also ensure each beverage has a category set.在保存之前,除了将饮料集合设置为类别之外,您还应该确保每种饮料都有一个类别集。 Here's a tweak to your service method with comments highlighting this.这是对您的服务方法的一个调整,评论突出了这一点。

    public CategoryEntity addCategory(CategoryRequest request) {

        List<BeveragesModel> beveragesModel = request.getCategory().getBeverages();
        
        CategoryEntity categoryEntity = CategoryEntity.builder()
                .categoryName(request.getCategory().getCategoryName())
                .build();

        List<BeveragesEntity> beveragesEnties = new ArrayList<>();
        if (!beveragesModel.isEmpty()) {
            for (BeveragesModel model : beveragesModel) {
                BeveragesEntity beveragesEntity = BeveragesEntity.builder()
                        .name(model.getName())
                        .price(model.getPrice())
                        .category(categoryEntity) // set category in each beverage
                        .build();
                beveragesEnties.add(beveragesEntity);
            }
        }

        categoryEntity.setBeverages(beveragesEnties); // set beverages in category

        return categoryRepository.save(categoryEntity);
    }

As you are returning the identities themselves from the controller there is a circular dependency between CategoryEntity and BeveragesEntity so you need to prevent this.当您从 controller 返回身份本身时,CategoryEntity 和 BeveragesEntity 之间存在循环依赖关系,因此您需要防止这种情况发生。 In your case you want to include the categoryId in your beverages json objects so you can do this by adding the following annotations to the category field in BeveragesEntity.在您的情况下,您希望在饮料 json 对象中包含 categoryId,因此您可以通过将以下注释添加到 BeveragesEntity 中的类别字段来执行此操作。 I am not sure of how the client is handling the data returned, but including the categoryId is just duplicating the id that already in the category json object我不确定客户端如何处理返回的数据,但包括 categoryId 只是复制已经在类别 json object 中的 id

    @JsonProperty("categoryId")
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    @JsonIdentityReference(alwaysAsId = true)
    @ManyToOne
    @JoinColumn(name = "CATEGORY_ID")
    private CategoryEntity category;

I implemented your code and made the above changes above and the response back from the controller was as follows我实现了您的代码并在上面进行了上述更改,从 controller 返回的响应如下

{
    "id": 1,
    "categoryName": "Alkoholna pica",
    "beverages": [
        {
            "id": 2,
            "name": "Ozujsko",
            "price": 16.0,
            "categoryId": 1
        },
        {
            "id": 3,
            "name": "Stella Artois",
            "price": 18.0,
            "categoryId": 1
        }
    ]
}

Lastly I would avoid using Lombok with Entities, particularly as @Data will autogenerate equals and hashcode methods and you want to ensure they are implemented correctly as you are using database generated identifiers article here最后,我会避免将 Lombok 与 Entities 一起使用,特别是因为 @Data 将自动生成 equals 和 hashcode 方法,并且您希望确保它们在您使用数据库生成的标识符文章时正确实现这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM