唯一索引或主键违规:

问题描述 投票:0回答:2

项目有5个包。

域名包类:

类别类

@Data
@Entity
public class Category {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String description;

    @ManyToMany(mappedBy = "categories")
    private Set<Recipe> recipes;
}

成分类别

@Data
@Entity
public class Ingredient {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private Long id;
        
            private String description;
            private BigDecimal amount;
        
            @OneToOne(fetch = FetchType.EAGER)
            private UnitOfMeasure uom;
            @ManyToOne
            private Recipe recipe;
        
        
            public Ingredient() {
            }
        
            public Ingredient(String description, BigDecimal amount, UnitOfMeasure uom) {
                this.description = description;
                this.amount = amount;
                this.uom = uom;
            }
    }

笔记课

@Data
@Entity
public class Notes {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne
    private Recipe recipe;

    @Lob
    private String recipeNotes;


}

菜谱课

@Data
@Entity
public class Recipe {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String description;
    private Integer prepTime;
    private Integer cookTime;
    private Integer servings;
    private String source;
    private String url;

    @Lob
    private String directions;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "recipe")
    private Set<Ingredient> ingredients = new HashSet<>();

    @Lob
    private Byte[] image;

    @Enumerated(value = EnumType.STRING)
    private Difficulty difficulty;

    @OneToOne(cascade = CascadeType.ALL)
    private Notes notes;


    @ManyToMany
    @JoinTable(name = "recipe_category",
            joinColumns = @JoinColumn(name = "recipe_id"),
            inverseJoinColumns = @JoinColumn(name = "category_id"))
    private Set<Category> categories = new HashSet<>();
}

测量单位类

@Data
@Entity
public class UnitOfMeasure {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String description;
}

Bootstrap 包 RecipeBootstrap 类

@Component
public class RecipeBootstrap implements ApplicationListener<ContextRefreshedEvent> {

    private final RecipeRepository recipeRepository;
    private final CategoryRepository categoryRepository;
    private final UnitOfMeasureRepository unitOfMeasureRepository;

    public RecipeBootstrap(RecipeRepository recipeRepository, CategoryRepository categoryRepository, UnitOfMeasureRepository unitOfMeasureRepository) {
        this.categoryRepository = categoryRepository;
        this.unitOfMeasureRepository = unitOfMeasureRepository;
        this.recipeRepository = recipeRepository;
    }
    
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        recipeRepository.saveAll(getRecipe());
    }
    
    public List<Recipe> getRecipe(){

        List<Recipe> recipes = new ArrayList<>(2);

        Optional<Category> americanCategoryOptional = categoryRepository.findByDescription("American");
        Optional<Category> mexicanCategoryOptional = categoryRepository.findByDescription("Mexican");
        Optional<Category> italianCategoryOptional = categoryRepository.findByDescription("Italian");
        Optional<Category> fastFoodCategoryOptional = categoryRepository.findByDescription("Fast Food");

        Category americanCategory = americanCategoryOptional.get();
        Category mexicanCategory = mexicanCategoryOptional.get();
        Category italianCategory = italianCategoryOptional.get();
        Category fastFoodCategory = fastFoodCategoryOptional.get();
        
        Optional<UnitOfMeasure> teaspoonUomOptional = unitOfMeasureRepository.findByDescription("Teaspoon");
        Optional<UnitOfMeasure> tablespoonUomOptional = unitOfMeasureRepository.findByDescription("Tablespoon");
        Optional<UnitOfMeasure> cupUomOptional = unitOfMeasureRepository.findByDescription("Cup");
        Optional<UnitOfMeasure> pinchUomOptional = unitOfMeasureRepository.findByDescription("Pinch");
        Optional<UnitOfMeasure> ounceUomOptional = unitOfMeasureRepository.findByDescription("Ounce");
        Optional<UnitOfMeasure> eachUomOptional = unitOfMeasureRepository.findByDescription("Each");
        Optional<UnitOfMeasure> dashUomOptional = unitOfMeasureRepository.findByDescription("Dash");

        UnitOfMeasure teaspoonUom = teaspoonUomOptional.get();
        UnitOfMeasure tablespoonUom = tablespoonUomOptional.get();
        UnitOfMeasure cupUom = cupUomOptional.get();
        UnitOfMeasure pinchUom = pinchUomOptional.get();
        UnitOfMeasure ounceUom = ounceUomOptional.get();
        UnitOfMeasure eachUom = eachUomOptional.get();
        UnitOfMeasure dashUom = dashUomOptional.get();

        Recipe guacRecipe = new Recipe();
        guacRecipe.setDescription("Perfect Guacamole");
        guacRecipe.setPrepTime(10);
        guacRecipe.setCookTime(0);
        guacRecipe.setDifficulty(Difficulty.EASY);
        guacRecipe.setDirections("The trick to making perfect guacamole is using avocados that are just the right amount of ripeness. Not ripe enough and the avocado will be hard and flavorless. Too ripe and the taste will be off.\n" +
                "\n" +
                "Check for ripeness by gently pressing the outside of the avocado. If there is no give, the avocado is not ripe yet. If there is a little give, the avocado is ripe. If there is a lot of give, the avocado may be too ripe and not good. In this case, taste test first before using.");

        Notes guacNotes = new Notes();
        guacNotes.setRecipeNotes("Guacamole has a role in the kitchen beyond a party dip. It's great scooped on top of nachos and also makes an excellent topping or side for enchiladas, tacos, grilled salmon, or oven-baked chicken.\n" +
                "\n" +
                "Guacamole is great in foods, as well. Try mixing some into a tuna sandwich or your next batch of deviled eggs.");

        guacNotes.setRecipe(guacRecipe);
        guacRecipe.setNotes(guacNotes);

        guacRecipe.getCategories().add(americanCategory);
        guacRecipe.getCategories().add(mexicanCategory);

        guacRecipe.getIngredients().add(new Ingredient("ripe avocados", new BigDecimal(5),teaspoonUom));
        guacRecipe.getIngredients().add(new Ingredient("Kosher salt", new BigDecimal(".5"),eachUom));
        guacRecipe.getIngredients().add(new Ingredient("fresh lime juice and lemon juice", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("minced red onion or thinly sliced green onion", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("serrano chiles, stems and seeds removed, minced", new BigDecimal(2),eachUom));
        guacRecipe.getIngredients().add(new Ingredient("Cilantro", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("freshly grated black pepper", new BigDecimal(2),dashUom));
        guacRecipe.getIngredients().add(new Ingredient("ripe tomato, seeds and pulp removed, chopped", new BigDecimal(".5"),eachUom));

        recipes.add(guacRecipe);
        
        return recipes;
    }
}

这是数据.sql

INSERT INTO category (description) VALUES ('American');
INSERT INTO category (description) VALUES ('Italian');
INSERT INTO category (description) VALUES ('Mexican');
INSERT INTO category (description) VALUES ('Fast Food');
INSERT INTO unit_of_measure (description) VALUES ('Teaspoon');
INSERT INTO unit_of_measure (description) VALUES ('Tablespoon');
INSERT INTO unit_of_measure (description) VALUES ('Cup');
INSERT INTO unit_of_measure (description) VALUES ('Pinch');
INSERT INTO unit_of_measure (description) VALUES ('Ounce');
INSERT INTO unit_of_measure (description) VALUES ('Each');
INSERT INTO unit_of_measure (description) VALUES ('Dash');
INSERT INTO unit_of_measure (description) VALUES ('Pint');

当我运行程序时出现错误。

org.springframework.dao.DataIntegrityViolationException: could not execute statement [Unique index or primary key violation: "PUBLIC.CONSTRAINT_INDEX_1 ON PUBLIC.INGREDIENT(UOM_ID NULLS FIRST) VALUES ( /* 1 */ CAST(2 AS BIGINT) )"; SQL statement:
insert into ingredient (amount,description,recipe_id,uom_id,id) values (?,?,?,?,default) [23505-214]] [insert into ingredient (amount,description,recipe_id,uom_id,id) values (?,?,?,?,default)]; SQL [insert into ingredient (amount,description,recipe_id,uom_id,id) values (?,?,?,?,default)]; constraint ["PUBLIC.CONSTRAINT_INDEX_1 ON PUBLIC.INGREDIENT(UOM_ID NULLS FIRST) VALUES ( /* 1 */ CAST(2 AS BIGINT) )"; SQL statement:
insert into ingredient (amount,description,recipe_id,uom_id,id) values (?,?,?,?,default) [23505-214]]

我找到原因了。它在这里。

guacRecipe.getIngredients().add(new Ingredient("ripe avocados", new BigDecimal(5),teaspoonUom));
        guacRecipe.getIngredients().add(new Ingredient("Kosher salt", new BigDecimal(".5"),eachUom));
        guacRecipe.getIngredients().add(new Ingredient("fresh lime juice and lemon juice", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("minced red onion or thinly sliced green onion", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("serrano chiles, stems and seeds removed, minced", new BigDecimal(2),eachUom));
        guacRecipe.getIngredients().add(new Ingredient("Cilantro", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("freshly grated black pepper", new BigDecimal(2),dashUom));
        guacRecipe.getIngredients().add(new Ingredient("ripe tomato, seeds and pulp removed, chopped", new BigDecimal(".5"),eachUom));

当创建具有相同测量单位的新成分时,会引发异常。例如,如果我写

guacRecipe.getIngredients().add(new Ingredient("ripe avocados", new BigDecimal(5),teaspoonUom));
        guacRecipe.getIngredients().add(new Ingredient("Kosher salt", new BigDecimal(".5"),eachUom));
       guacRecipe.getIngredients().add(new Ingredient("Cilantro", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("freshly grated black pepper", new BigDecimal(2),dashUom));

运行没有问题。如果我添加相同的unitOfMeasure,则会引发异常。例如:

guacRecipe.getIngredients().add(new Ingredient("ripe avocados", new BigDecimal(5),teaspoonUom));
        guacRecipe.getIngredients().add(new Ingredient("Kosher salt", new BigDecimal(".5"),eachUom));
      guacRecipe.getIngredients().add(new Ingredient("Cilantro", new BigDecimal(2),tablespoonUom));
        guacRecipe.getIngredients().add(new Ingredient("freshly grated black pepper", new BigDecimal(2),dashUom));
        guacRecipe.getIngredients().add(new Ingredient("ripe tomato, seeds and pulp removed, chopped", new BigDecimal(".5"),eachUom));

eachUom 被写入两次。我找不到这个问题的正确答案。

java spring spring-boot hibernate spring-data
2个回答
0
投票

问题的出现是因为您在 Ingredient 和 UnitOfMeasure 表之间有 @OneToOne 映射,但您试图将 unitOfMeasure 表的主键添加两次作为成分表中的外键。

抛出异常是因为您使用了一对一关系,但为多种成分添加了相同的测量单位。

如果你想摆脱这个错误,你可以在成分表中使用@OneToMany关系,因为一种成分可以有多个unitOfMeasure。


0
投票

我遇到了同样的问题,并通过更改依赖项来解决。只需确保您使用

javax.persistence
代替
GeneratedValue

© www.soinside.com 2019 - 2024. All rights reserved.