Home > Net >  @JoinColumn "occurs out of order" when upgrading to spring-boot-3 (Hibernate 6 )
@JoinColumn "occurs out of order" when upgrading to spring-boot-3 (Hibernate 6 )

Time:12-21

I have the following usage in JoinColumns

@Entity
public class EntityOne{

  private String action;
  private String type;

  @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
  @NotFound(action = NotFoundAction.IGNORE)
  @JoinColumns({
      @JoinColumn(name = "action", referencedColumnName = "action_name", updatable = false, insertable = false),
      @JoinColumn(name = "type", referencedColumnName = "type_name", updatable = false, insertable = false)
  })
  private Entitytwo entitytwo;
  }

And

@Entity
public class EntityTwo {

  @Id
  @Column(name = "type_name")
  private String typeName;

  @Id
  @Column(name = "action_name")
  private String actionName;

  }

This setup causes hibernate error of

Referenced column '"   column.getName()
                                      "' mapped by target property '"   property.getName()
                                      "' occurs out of order in the list of '@JoinColumn's

If i change the order inside the @JoinColumns it seems to work, but can stop working at the next time the application starts.

The hibernate comments at the begining of the relevant code states:

    // Now we need to line up the properties with the columns in the
    // same order they were specified by the @JoinColumn annotations
    // this is very tricky because a single property might span
    // multiple columns.
    // TODO: For now we only consider the first property that matched
    //       each column, but this means we will reject some mappings
    //       that could be made to work for a different choice of
    //       properties (it's also not very deterministic)

And on the relevant code itself:

            // we have the first column of a new property
            orderedProperties.add( property );
            if ( property.getColumnSpan() > 1 ) {
                if ( !property.getColumns().get(0).equals( column ) ) {
                    // the columns have to occur in the right order in the property
                    throw new AnnotationException("Referenced column '"   column.getName()
                              "' mapped by target property '"   property.getName()
                              "' occurs out of order in the list of '@JoinColumn's");
                }
                currentProperty = property;
                lastPropertyColumnIndex = 1;
            }

How should i set the @JoinColumn for it to consistently work?

CodePudding user response:

If the action and type attributes of EntityOne are meant to refer to the corresponding attributes of EntityTwo, they are useless and misleading.

The attribute private Entitytwo entitytwo is enough to design the @ManytoOne relation.

Remove these two attributes and if you need to get the action and type value of the entityTwo linked to an entityOne, simply use entityOne.entitytwo.getAction() (or entityOne.entitytwo.getType()).

CodePudding user response:

I just tried the code you posted in Hibernate 6.1, and I observed no error. Even after permuting various things, still no error. So then to make things harder, I added a third column to the FK and tried permuting things. Still no error.

I now have:

@Entity
public class EntityOne {

  @Id @GeneratedValue
  Long id;

  String action;
  String type;
  int count;

  @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
  @NotFound(action = NotFoundAction.IGNORE)
  @JoinColumns({
          @JoinColumn(name = "count", referencedColumnName = "count", updatable = false, insertable = false),
          @JoinColumn(name = "action", referencedColumnName = "action_name", updatable = false, insertable = false),
          @JoinColumn(name = "type", referencedColumnName = "type_name", updatable = false, insertable = false),
  })
  EntityTwo entitytwo;
}

@Entity
public class EntityTwo {

  @Id
  @Column(name = "type_name")
  String typeName;

  @Id
  @Column(name = "count")
  int count;

  @Id
  @Column(name = "action_name")
  String actionName;

}

and the test code:

@DomainModel(annotatedClasses = {EntityOne.class, EntityTwo.class})
@SessionFactory
public class BugTest {
    @Test
    public void test(SessionFactoryScope scope) {
        scope.inTransaction( session -> {
            EntityOne entityOne = new EntityOne();
            entityOne.action = "go";
            entityOne.type = "thing";
            EntityTwo entityTwo = new EntityTwo();
            entityTwo.actionName = "go";
            entityTwo.typeName = "thing";
            entityOne.entitytwo = entityTwo;
            session.persist( entityOne );
        } );
    }
}

Perhaps there's something you're not telling us? Like, for example, something to do with the @Id of EntityOne which is missing in your original posted code?

Just in case, also tried this variation:

@Entity
public class EntityOne {

  @Id
  String action;
  @Id
  String type;
  @Id
  int count;

  @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
  @NotFound(action = NotFoundAction.IGNORE)
  @JoinColumns({
          @JoinColumn(name = "action", referencedColumnName = "action_name", updatable = false, insertable = false),
          @JoinColumn(name = "count", referencedColumnName = "count", updatable = false, insertable = false),
          @JoinColumn(name = "type", referencedColumnName = "type_name", updatable = false, insertable = false),
  })
  EntityTwo entitytwo;
}

But still no error.

  • Related