【问题标题】:@JoinColumn "occurs out of order" when upgrading to spring-boot-3 (Hibernate 6 )@JoinColumn 升级到 spring-boot-3 (Hibernate 6) 时“出现乱序”
【发布时间】:2022-12-21 07:55:58
【问题描述】:

我在 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;
  }

@Entity
public class EntityTwo {

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

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

  }

此设置导致休眠错误

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

如果我更改 @JoinColumns 中的顺序,它似乎可以工作,但可以在下次应用程序启动时停止工作。

相关代码开头的 hibernate cmets 状态:

    // 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)

在相关代码本身:

            // 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;
            }

我应该如何设置 @JoinColumn 以使其始终如一地工作?

【问题讨论】:

  • 这是一个非常奇怪的要求。如果没有错误,请提交错误,因为 JPA 对注释和 java 属性的排序没有要求。可能会显示堆栈和错误消息,因为它可能指示更多可能指向更好解决方法的上下文。
  • 你有什么进步吗?我遇到了同样的问题。你有没有用hibernate提出这个问题。对我来说这似乎是一个错误
  • @Chris - 不,我的团队在更高优先级的任务到来时放弃了它。我会回来的。 No 没有提出这个问题,因为从上面的文档来看它似乎是故意的。

标签: spring-boot hibernate jpa spring-boot-3 hibernate-6.x


【解决方案1】:

如果EntityOneactiontype 属性是指EntityTwo 的相应属性,那么它们是无用的且具有误导性。

private Entitytwo entitytwo属性足以设计@ManytoOne关系。

删除这两个属性,如果您需要获取链接到entityOneentityTwoactiontype值,只需使用entityOne.entitytwo.getAction()(或entityOne.entitytwo.getType())。

【讨论】:

  • 你能解释一下为什么“无用和误导”吗?这不是 @JoinColumns 的用途吗?
  • @JoinColumn 会定义数据库中存储外键的列名(同时也是针对目标表中主键的列),但在关系对象模型上,它不需要出现:换句话说,它隐藏在“entitytwo”java 属性后面。并且,即使EntityTwo的主键依赖2个属性,用@ManyToOne注解的entitytwo属性就足够了。
  • 您是说该模型不需要 EntityOne.action 和类型字符串属性吗?它们并非无用或误导,因为通常希望单独引用值,并且可以允许在不执行连接和其他性能考虑的情况下进行提取。如果您有 fk 值,则不需要使用 EntityOne 序列化(并因此获取)完整的 entityTwo 实体。
  • 如果不是无用,那就是多余的。因此它误导了休眠机制。如果你真的害怕获取entitytwo来获取这些信息,你可以尝试保留它们但添加一个注释来定义列名以匹配@joinColumn上给出的列名。但是,如果您在 entityOne 表的列类型和操作上正确设置索引,则连接不会很昂贵。
【解决方案2】:

我刚刚尝试了您在 Hibernate 6.1 中发布的代码,没有发现任何错误。即使在排列各种东西之后,仍然没有错误。因此,为了让事情变得更难,我在 FK 中添加了第三列并尝试排列。仍然没有错误。

我现在有:

@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;

}

和测试代码:

@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 );
        } );
    }
}

也许有什么事你没有告诉我们?例如,与 EntityOne@Id 有关的内容在您的原始发布代码中丢失了?

【讨论】:

    猜你喜欢
    • 2022-12-04
    • 2023-02-04
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    • 2016-12-04
    • 1970-01-01
    相关资源
    最近更新 更多