Java/Hibernate:如何检测字段是否是延迟加载的代理而不是实际数据?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15890559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 21:11:09  来源:igfitidea点击:

Java/Hibernate: How to detect, if field is lazy-loaded proxy and not actual data?

javahibernatelazy-loadingdto

提问by Miro Hudak

I'm converting my entity to DTO and I want to set NULL as DTO value for all fields, which are lazy-loaded and not initialized (because I do not want to transfer all the data all the time).

我正在将我的实体转换为 DTO,并且我想将 NULL 设置为所有字段的 DTO 值,这些字段是延迟加载且未初始化的(因为我不想一直传输所有数据)。

I've tried:

我试过了:

if (!(entity.getNationality() instanceof HibernateProxy))
    this.setNationalityFromEntity(entity.getNationality());

But it did not seemed to help. Any suggestions are welcome!

但这似乎没有帮助。欢迎任何建议!

Thank you!

谢谢!

回答by DuncanKinnear

They way we do this in our Entities is we have boolean methods which do the check in a way that will not trigger the lazy loading. For example, if our Entity had an associated entity called 'associatedSomething', then the method to check if that associated Entity has been lazy loaded would be:

我们在我们的实体中这样做的方式是我们有布尔方法,它们以不会触发延迟加载的方式进行检查。例如,如果我们的实体有一个名为“关联的东西”的关联实体,那么检查关联实体是否已延迟加载的方法将是:

    public boolean isAssociatedSomethingLoaded() {
        if (associatedSomething instanceof HibernateProxy) {
            if (((HibernateProxy)associatedSomething).getHibernateLazyInitializer().isUninitialized()) {
                return false;
            }
        }
        return (getAssociatedSomething() != null);
    }

NOTE: It's important not to use getAssociatedSomething()in the check, as this makes sure that the associated Entity does not get lazy-loaded during the check.

注意:重要的是不要getAssociatedSomething()在检查中使用,因为这可以确保关联的实体在检查期间不会被延迟加载。

回答by Affe

The class is always a proxy, whether it's initialized or not, so you're going to exclude it every time if you just check for instances of proxy. The Lazy Load does not cause the Proxy reference on the entity to be replaced with a reference to a new object, it just populates the fields.

该类始终是一个代理,无论它是否已初始化,因此如果您只是检查代理实例,则每次都将排除它。延迟加载不会导致实体上的代理引用被替换为对新对象的引用,它只是填充字段。

To find out if it's actually initialized you need to ask it!

要确定它是否真正初始化,您需要询问它!

if (HibernateProxy.class.isInstance(entity.getNationality())) {
  HibernateProxy proxy = HibernateProxy.class.cast(entity.getNationality());
  if (!proxy.getHibernateLazyInitializer().isUninitialized()) {
    this.setNationalityFromEntity(entity.getNationality());
  }
}

回答by Christian Beikov

The mere possibility of being able to invoke a getter for some state that shouldn't be available for a use case is problematic in my opinion, but that's a different story. I would suggest you implement a proper DTO approach instead to avoid accidental errors.

在我看来,能够为某些不应该用于用例的状态调用 getter 的可能性是有问题的,但这是另一回事。我建议您实施适当的 DTO 方法来避免意外错误。

I created Blaze-Persistence Entity Viewsfor exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.

我正是为那个用例创建了Blaze-Persistence 实体视图。您本质上将 JPA 实体的 DTO 定义为接口并将它们应用于查询。它支持映射嵌套的 DTO、集合等,基本上是您期望的所有内容,除此之外,它将提高您的查询性能,因为它将生成查询,仅获取您实际需要的 DTO 数据。

The entity views for your example could look like this

您示例的实体视图可能如下所示

@EntityView(Person.class)
interface PersonDto {
  String getNationality();
}

Querying could look like this

查询可能看起来像这样

List<PersonDto> dtos = entityViewManager.applySetting(
  EntityViewSetting.create(PersonDto.class),
  criteriaBuilderFactory.create(em, Person.class)
).getResultList();