Java Hibernate - 无法添加或更新子行

时间:2014-06-30 01:22:57

标签: java spring hibernate jpa

我遇到了Hibernate的一个问题,我无法找到其他任何地方的答案。我在StackOverflow上尝试了这里的建议,但我看不出我的代码在这里与工作示例有什么不同。每当我尝试运行我的集成测试(下面列出)时,它都会失败并显示外键约束失败消息(错误和相关文件的完整详细信息如下)。

我做错了什么?

错误讯息:

org.hibernate.exception.ConstraintViolationException: could not insert: [net.redacted.miseenplace.domain.IngredientInstance]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2345)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2852)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:320)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:713)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:701)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:697)
    at net.redacted.miseenplace.service.impl.HibernateDao.add(HibernateDao.java:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy22.add(Unknown Source)
    at net.redacted.miseenplace.integration.RecipeIntegrationTest.recipeIntegrationTest(RecipeIntegrationTest.java:52)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`miseenplace`.`ingredient_instance`, CONSTRAINT `FK15EDCF432DFAC9AF` FOREIGN KEY (`id`) REFERENCES `recipe` (`recipeId`))
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
    at com.mysql.jdbc.Util.getInstance(Util.java:381)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1015)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2019)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1937)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1922)
    at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
    ... 57 more

RecipeIntegrationTest

package net.redacted.miseenplace.integration;

import org.hibernate.mapping.Set;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;

import net.redacted.miseenplace.DomainAwareBase;
import net.redacted.miseenplace.domain.Ingredient;
import net.redacted.miseenplace.domain.IngredientInstance;
import net.redacted.miseenplace.domain.Recipe;
import net.redacted.miseenplace.service.dao.IngredientDao;
import net.redacted.miseenplace.service.dao.IngredientInstanceDao;
import net.redacted.miseenplace.service.dao.RecipeDao;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;

import static org.junit.Assert.*;

@ContextConfiguration(locations = "/persistence-beans.xml")
public class RecipeIntegrationTest extends DomainAwareBase{

    @Autowired
    private IngredientDao ingredientDao;

    @Autowired
    private IngredientInstanceDao ingredientInstanceDao;

    @Autowired
    private RecipeDao recipeDao;

    @Test
    public void recipeIntegrationTest(){
        Recipe recipe = new Recipe("Integration Test Recipe");

        //Add Instructions
        LinkedHashSet<String> instructions = new LinkedHashSet<String>();
        instructions.add("This is an instruction.");

        recipe.setRecipeSteps(instructions);
        recipeDao.add(recipe);

        Ingredient cookingOil = new Ingredient("Cooking Oil");
        ingredientDao.add(cookingOil);

        //Create IngredientInstances
        IngredientInstance iCookingOil = new IngredientInstance("1/8 cup", cookingOil);
        iCookingOil.setRecipe(recipe);
        ingredientInstanceDao.add(iCookingOil);

        //Add IngredientInstances to recipe
        HashSet<IngredientInstance> inginst = new HashSet<IngredientInstance>();
        //inginst.add(iCookingOil);

        recipe.setRecipeIngredients(inginst);

        recipeDao.update(recipe);

        recipe.prettyPrint();
    }

}

配方

package net.redacted.miseenplace.domain;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "recipe")
public class Recipe {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long recipeId;

    private String recipeName;
    private LinkedHashSet<String> recipeSteps;

    @OneToMany(mappedBy="recipe")
    private Set<IngredientInstance> recipeIngredients;

    protected Recipe() {
    }

    public Recipe(String recipeName) {
        this.recipeName = recipeName;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Recipe other = (Recipe) obj;
        if (recipeIngredients == null) {
            if (other.recipeIngredients != null)
                return false;
        } else if (!recipeIngredients.equals(other.recipeIngredients))
            return false;
        if (recipeName == null) {
            if (other.recipeName != null)
                return false;
        } else if (!recipeName.equals(other.recipeName))
            return false;
        if (recipeSteps == null) {
            if (other.recipeSteps != null)
                return false;
        } else if (!recipeSteps.equals(other.recipeSteps))
            return false;
        return true;
    }

    public long getId() {
        return recipeId;
    }

    public HashSet<IngredientInstance> getRecipeIngredients() {
        return (HashSet<IngredientInstance>)recipeIngredients;
    }

    public String getRecipeName() {
        return recipeName;
    }

    public LinkedHashSet<String> getRecipeSteps() {
        return recipeSteps;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime
                * result
                + ((recipeIngredients == null) ? 0 : recipeIngredients
                        .hashCode());
        result = prime * result
                + ((recipeName == null) ? 0 : recipeName.hashCode());
        result = prime * result
                + ((recipeSteps == null) ? 0 : recipeSteps.hashCode());
        return result;
    }

    public void setRecipeIngredients(
            HashSet<IngredientInstance> recipeIngredients) {
        this.recipeIngredients = recipeIngredients;
    }

    public void setRecipeName(String recipeName) {
        this.recipeName = recipeName;
    }

    public void setRecipeSteps(LinkedHashSet<String> recipeSteps) {
        this.recipeSteps = recipeSteps;
    }

    @Override
    public String toString() {
        return "Recipe [id=" + recipeId + ", recipeName=" + recipeName
                + ", recipeSteps=" + recipeSteps + ", recipeIngredients="
                + recipeIngredients + "]";
    }

    public void prettyPrint() {
        //Header with title
        System.out.println("");
        System.out.println("=========================================================");
        System.out.println(this.recipeId + " : " + this.recipeName);
        System.out.println("---------------------------------------------------------");
        System.out.println("Ingredients");
        for(IngredientInstance ii : this.recipeIngredients) {
            System.out.println("\t" + ii.getQuantity() + "\t" + ii.getIngredient().getIngredientName() + "\t" + "(" + ii.getIngredient().getIngredientId() + ")");
        }
        System.out.println("");
        System.out.println("---------------------------------------------------------");
        System.out.println("Steps:");
        for(String ss : this.recipeSteps) {
            System.out.println("\t" + ss);
        }
        System.out.println("");
        System.out.println("=========================================================");
    }

}

IngredientInstance

package net.redacted.miseenplace.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import net.redacted.miseenplace.domain.Ingredient;
import net.redacted.miseenplace.domain.Recipe;

@Entity
@Table(name = "ingredient_instance")
public class IngredientInstance {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long ingredientInstanceId;

    @ManyToOne
    @JoinColumn(name="recipeId")
    private Recipe recipe;

    private String quantity;

    @ManyToOne
    @JoinColumn(name="id")
    private Ingredient ingredient;

    protected IngredientInstance() {
    }

    public IngredientInstance(String quantity, Ingredient ingredient) {
        this.quantity = quantity;
        this.ingredient = ingredient;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IngredientInstance other = (IngredientInstance) obj;
        if (ingredient == null) {
            if (other.ingredient != null)
                return false;
        } else if (!ingredient.equals(other.ingredient))
            return false;
        if (quantity == null) {
            if (other.quantity != null)
                return false;
        } else if (!quantity.equals(other.quantity))
            return false;
        return true;
    }

    public Ingredient getIngredient() {
        return ingredient;
    }

    public long getIngredientInstanceId() {
        return ingredientInstanceId;
    }

    public String getQuantity() {
        return quantity;
    }

    public Recipe getRecipe() {
        return recipe;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((ingredient == null) ? 0 : ingredient.hashCode());
        result = prime * result
                + ((quantity == null) ? 0 : quantity.hashCode());
        return result;
    }

    public void setIngredient(Ingredient ingredient) {
        this.ingredient = ingredient;
    }

    public void setQuantity(String quantity) {
        this.quantity = quantity;
    }

    public void setRecipe(Recipe recipe) {
        this.recipe = recipe;
    }

    @Override
    public String toString() {
        return "IngredientInstance [id=" + ingredientInstanceId + ", quantity=" + quantity
                + ", ingredient=" + ingredient + "]";
    }
}

1 个答案:

答案 0 :(得分:0)

您持久存在一个不在持久化上下文中的对象Recipe。 这意味着你正在尝试添加没有持久配方的配方 尝试做以下事情:

 @Test
    public void recipeIntegrationTest(){
        Recipe recipe = new Recipe("Integration Test Recipe");

        //Add Instructions
        LinkedHashSet<String> instructions = new LinkedHashSet<String>();
        instructions.add("This is an instruction.");

        recipe.setRecipeSteps(instructions);


  //get the persisted recipe
 recipe =    recipeDao.add(recipe);

        Ingredient cookingOil = new Ingredient("Cooking Oil");
        ingredientDao.add(cookingOil);

        //Create IngredientInstances
        IngredientInstance iCookingOil = new IngredientInstance("1/8 cup", cookingOil);
        iCookingOil.setRecipe(recipe);
        ingredientInstanceDao.add(iCookingOil);

        //Add IngredientInstances to recipe
        HashSet<IngredientInstance> inginst = new HashSet<IngredientInstance>();
        //inginst.add(iCookingOil);

        //recipe.setRecipeIngredients(inginst); --> you don't need to do this unless //you have new persisted ingredians



//          recipeDao.update(recipe); update is not needed either

        recipe.prettyPrint();
    }