Java JPA - сохранить структуру «многие ко многим» в БД - ошибка: попытка присвоить идентификатор из нулевого свойства «один к одному» - PullRequest
0 голосов
/ 05 мая 2018

Я пытаюсь сохранить конструкцию «многие ко многим» в моей БД с помощью 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)

1 Ответ

0 голосов
/ 09 мая 2018

Благодаря crizzis и xerx593:

По-видимому, в MealPlan MealPlan.mealplanrecipe не был инициализирован И в каждом MealPlan.mealplanrecipe объект PK также должен быть инициализирован. Я забыл это, хотя Java это делает .. Я добавил:

public void setDefaultPKObject(){
    this.mealplanrecipePK = new MealPlanRecipePK();
}

и запустите это для каждого элемента в MealPlan.mealplanrecipe

...