Я пытаюсь сохранить конструкцию «многие ко многим» в моей БД с помощью JPA. Есть Рецепты и MealPlans, и у MealPlan может быть много Рецептов. И рецепт может быть в нескольких MealPlans.
Классы: Рецепт и MealPlan .
Таблица соответствия: MealPlanRecipe состоит из recipe_id
, mealplan_id
и атрибута порций .
Я генерирую MealPlan и хочу сохранить в БД, создав ошибку. Смотрите все ниже и большое спасибо заранее !! Chris
-
класс Рецепт:
@Entity(name = "Recipe")
@Table(name = "recipe")
@XmlRootElement
public class Recipe implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 255)
@Column(name = "name")
private String name;
[...]
класс MealPlan:
@Entity(name = "MealPlan")
@Table(name = "mealplan")
@XmlRootElement
public class MealPlan implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 255)
@Column(name = "name")
String name;
@OneToMany(
mappedBy = "mealplan",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<MealPlanRecipe> mealplanrecipe = new ArrayList<>();
[...]
класс MealPlanRecipe:
@Entity(name = "MealPlanRecipe")
@Table(name = "mealplanrecipe")
@XmlRootElement
public class MealPlanRecipe implements Serializable {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("recipeId")
private Recipe recipe;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("mealplanId")
private MealPlan mealplan;
@EmbeddedId
protected MealPlanRecipePK mealplanrecipePK;
@Basic(optional = false)
@NotNull
@Column(name = "portions")
private int portions;
[...]
класс MealPlanRecipePK:
public class MealPlanRecipePK implements Serializable {
@Basic(optional = false)
@NotNull
@Column(name = "recipe_id")
private int recipeId;
@Basic(optional = false)
@NotNull
@Column(name = "mealplan_id")
private int mealplanId;
public MealPlanRecipePK() {
}
public MealPlanRecipePK(int recipeId, int mealplanId) {
this.recipeId = recipeId;
this.mealplanId = mealplanId;
}
public int getRecipeId() {
return recipeId;
}
public void setRecipeId(int recipeId) {
this.recipeId = recipeId;
}
public int getMealplanId() {
return mealplanId;
}
public void setMealplanId(int mealplanId) {
this.mealplanId = mealplanId;
}
@Override
public int hashCode() {
int hash = 7;
hash = 67 * hash + this.recipeId;
hash = 67 * hash + this.mealplanId;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MealPlanRecipePK other = (MealPlanRecipePK) obj;
if (this.recipeId != other.recipeId) {
return false;
}
if (this.mealplanId != other.mealplanId) {
return false;
}
return true;
}
}
Выполненный код:
MealPlan tosave;
[here, fill "tosave"-Object: Add Recipes to its ArrayList..]
if(tosave!=null){
this.sql.getEM().getTransaction().begin();
this.sql.getEM().persist(tosave);
this.sql.getEM().getTransaction().commit();
}
Вывод / ошибка:
javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [orm.MealPlanRecipe.mealplan]
javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [orm.MealPlanRecipe.mealplan]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
at com.mycompany.meallion.Menu.processRequest(Menu.java:74)
at com.mycompany.meallion.Menu.doGet(Menu.java:103)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [orm.MealPlanRecipe.mealplan]
at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:98)
at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:440)
at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:121)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:97)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:379)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:319)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:296)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:460)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:294)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
atorg.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
EDIT:
Я поместил этот цикл в код выполнения, чтобы установить все атрибуты MealPlanRecipe.mealplan:
for(MealPlanRecipe mpr : tosave.GetMealPlanRecipes()){
mpr.setMealplan(tosave);
}
Теперь я получаю эту ошибку:
javax.persistence.PersistenceException:
org.hibernate.PropertyAccessException: could not set a field value by
reflection setter of orm.MealPlanRecipePK.mealplanId
[...]
Caused by: java.lang.NullPointerException
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:57)
at sun.reflect.UnsafeIntegerFieldAccessorImpl.set(UnsafeIntegerFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:764)
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:122)