14

基本问题:为什么不总是实例化 @Embedded 对象?

有趣的观察是,如果 @Embedded 对象不包含基本数据类型(int、boolean ...)或之前没有被触及,Ebean 不会实例化这些对象。例子:

@Entity
public class Embedder {
    // getNotAutoInstantiated() will return null if this field was not touched before
    @Embedded
    private NotAutoInstantiated notAutoInstantiated = new NotAutoInstantiated();
    // getAutoInstantiated() will always return an instance!
    @Embedded
    private AutoInstantiated autoInstantiated = new AutoInstantiated();
}

@Embeddable
public class AutoInstantiated {
    // theKey is why this embedded object is always instantiated
    private int theKey; 
    private String field1;      
}

@Embeddable
public class NotAutoInstantiated {
    private String field2;      
}
4

4 回答 4

13

对于 Hibernate,您可能需要查看问题HHH-7610

特别是,从 5.1 开始,有一个实验特性可以改变这种行为。请注意,此功能存在已知问题,在稳定之前不应在生产中使用。这在org.hibernate.cfg.AvailableSettings的 Javadocs 中有详细说明):

/**
 * [EXPERIMENTAL] Enable instantiation of composite/embedded objects when all of its attribute values are {@code null}.
 * The default (and historical) behavior is that a {@code null} reference will be used to represent the
 * composite when all of its attributes are {@code null}
 * <p/>
 * This is an experimental feature that has known issues. It should not be used in production
 * until it is stabilized. See Hibernate Jira issue HHH-11936 for details.
 *
 * @since 5.1
 */
String CREATE_EMPTY_COMPOSITES_ENABLED = "hibernate.create_empty_composites.enabled";

hibernate.create_empty_composites.enabled属性设置为 true,瞧!

于 2016-11-28T10:05:02.537 回答
6

我不认为 JPA 规范清楚地描述了当@Embedded对象的属性全部为 null时会发生什么,但至少某些实现将具有 null 属性的对象视为 null 对象,这就是您所看到的。

这似乎是一个合理的实现。当然,它在我的代码(使用 Hibernate)中很有用,如果我将一个@Embedded对象设置为 null,我希望它在加载持久版本时保持为 null。

在您的示例中,AutoInstantiated该类永远不能被视为 null,因为原始属性theKey永远不能为 null。

于 2012-12-22T02:34:00.367 回答
4

我刚刚遇到了与 Hibernate 相同的问题。回答了关于“为什么”的原始问题。

但是要谈论一个解决方案,我只使用一个@PostLoad 方法,所以在类Embedder中是这样的:

@PostLoad
private void initData() {
  if(notAutoInstantiated == null) {
    notAutoInstantiated = new NotAutoInstantiated();
  }
}

更新:

警告!上面的代码可以工作,但确实有意想不到的副作用!一旦您从数据库加载带有空指针的对象,它就会被标记为脏,因为这个后加载代码!就我而言,这种副作用会导致来自线程的 SQL 更新命令,它应该只加载数据和搜索这个 bug 的时间!

于 2017-07-04T09:43:26.387 回答
1

与 Martin 类似的 hack,用于在未加载对象时避免 NPE 并避免副作用。

  // workaround as Embeddable objects are not loaded if all their fields are null
  public NotAutoInstantiated getNotAutoInstantiated() {
    if (notAutoInstantiated == null) {
      // WARNING! do not assign this new object to notAutoInstantiated field,
      // this would have side effects as the field is not loaded by Ebean, 
      // Ebean would try to refresh the field in some cases and another NPE would occur:
      // io.ebeaninternal.server.core.DefaultBeanLoader.refreshBeanInternal(DefaultBeanLoader.java:194)
      return new NotAutoInstantiated();
    }
    return notAutoInstantiated;
  }
于 2021-01-15T13:17:12.167 回答