@Embedded对象没有基本数据类型字段,则不会自动实例化



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

有趣的观察结果是,如果对象不包含基本数据类型(int,boolean...)或以前没有接触过,则Ebean不会实例化@Embedded对象。例:

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

对于休眠,您可能需要查看问题 HHH-7610。

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

/**
 * [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,瞧!

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

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

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

我刚刚在Hibernate上遇到了同样的问题。最初的问题,关于"为什么"得到了回答。

但是要谈论解决方案,我只使用@PostLoad方法,因此在类中嵌入器如下所示:

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

更新:

警告!上面的代码正在工作,但确实有一个意想不到的副作用!一旦你从数据库中加载了带有空指针的对象,它就会被标记为脏,因为这个后加载代码!就我而言,这种副作用会导致线程发出 SQL 更新命令,该命令应该只加载搜索此错误的数据和小时数!

与 Martin 类似的技巧,用于在对象未加载时避免 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;
  }

相关内容

  • 没有找到相关文章

最新更新