如何使用 Jackson 防止 Ebean 中的延迟加载?

How do I prevent Lazy loading in Ebean using Jackson?

我有以下场景:

public class ContrivedEntity extends Model {

    private Long id;
    private Shipper shipper;
    private Location location;
}

public class Shipper extends Model {

    private Long id;
    private Country country;

}

一个 ContrivedEntity 有几个关系,它的关系本身也有依赖关系...... 我创建了一个功能,用户可以在其中搜索人为的实体....此搜索功能不需要加载依赖项,但是当我使用 play 的助手 Json.toJson 序列化结果时,它会延迟加载其他依赖项在其他几个查询中...

我已经通过使用 Jackson Views(在我想在最终结果中忽略的实体中使用注释)设法防止了这种行为... 但我正在寻找可以在 Ebean 端完成的事情...在编写 EBean 查询时...

这种方式能防止延迟加载吗? 如果是 'No' 答案... Hibernate 是否提供此类功能? 任何帮助将不胜感激... 如果您需要更多上下文,请发表评论,我会编辑问题。

非常感谢

...but I'm looking for something that could be done on Ebean's end... while composing an Ebean query...

这是不可能的,很多人会喜欢这个功能(我 2),唯一明智的方法是创建专用模型 class 并用选定的数据填充它 "manually"。

使用反射也是一个不错的考虑方式,特别是如果您拥有针对许多不同情况的高级 REST api。

我认为您可以使用 Ebean 的 PathProperties 和 JSON 支持来完全按照您的意愿行事。 Ebean 具有良好的 JSON 内置支持,这是它这样做的原因之一。

也就是说,您可以使用 PathProperties 来定义您希望包含在 JSON 输出和查询中的属性。在当前的 Ebean 中,您使用 Query.apply(pathProperties) ... 来告诉查询要获取对象图的哪一部分。

一个例子:

PathProperties pathProperties =
        PathProperties.parse("(id,status,name,shippingAddress(id,line1,city),billingAddress(*),contacts(*))");

List<Customer> customers = Ebean.find(Customer.class)
    .apply(pathProperties)
    .findList();

String jsonString = Ebean.json().toJson(customers, pathProperties);
System.out.println(jsonString);

请注意,Ebean 现在在内部使用 Jackson 核心,因为它内置了 JSON 支持,并且 github 中还有一个 Jackson Ebean 模块,但尚未发布。

将 Jackson 视图映射到 Ebean 可能会很好 'pathProperties' 但我还没有看过。

希望对您有所帮助 干杯,罗伯

我试图找到像...这样简单的东西

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate4Module());
Json.setObjectMapper(mapper);

https://github.com/FasterXML/jackson-datatype-hibernate

感谢您的帮助

只是为了添加一个额外的选择。 Ebean 的 Query 现在也支持禁用延迟加载。

query.setDisableLazyLoading(true)

所以目前有这 3 个选项:

  1. Query.setDisableLazyLoading(真)
  2. 路径属性
  3. avaje-ebeanorm-jackson

我可能喜欢第 4 个选项,但它需要 time/effort。

我需要一个解决方案来避免在 Json.toJson 序列化期间由 ebean 延迟加载,并想出了这个。它非常毛茸茸,但它的优点是可以本地化到模型 class 并且可以与标准 Json.toJson.

一起正常工作

定义通用助手:

/**
 * Check if a lazy-loaded property on an ebean model class has been loaded without accidentally loading it
 * @param clazz The class instance of the object to check (T.class)
 * @param bean The actual object to check the property on
 * @param propertyName The name of the property to check
 * @param <T> The class of the object
 * @return Whether it has already been loaded or not
 */
public static <T> boolean isPropertyLoaded(Class<T> clazz, T bean, String propertyName) {
    // avoid ebean lazy loading by using the secret ebean api
    if (bean instanceof EntityBean) {
        // obtain the ebean descriptor of the class and property
        BeanDescriptor<T> beanDescriptor = ((SpiEbeanServer) Oracle.getCurrent()).getBeanDescriptor(clazz);
        BeanProperty property = beanDescriptor.getBeanProperty(propertyName);
        EntityBean eb = (EntityBean) bean;
        EntityBeanIntercept ebi = eb._ebean_getIntercept();
        // is this the simple case?
        if (!ebi.isLoadedProperty(property.getPropertyIndex())) return false;
        // if it is a list, check if it is populated
        Object value = property.getValue(eb);
        if (value instanceof BeanList) {
            BeanList list = (BeanList) value;
            // if it is marked as loaded and is not null
            return list.isPopulated();
        }
    }
    return true;
}

然后在ebean模型class上,这样使用:

@JsonIgnore
@ManyToMany(fetch=LAZY)
@JoinTable(...)
public List<RelatedEntity> relatedEntities;

// getter used during JSON serialize to avoid ebean lazy loading
@JsonProperty("relatedEntities")
@JsonInclude(JsonInclude.Include.NON_NULL)
public List<RelatedEntity> getJsonRelatedEntities() {
    if (Helper.isPropertyLoaded(ThisEntity.class, this, "relatedEntities")) {
        return relatedEntities;
    } else {
        return null;
    }
}