如何使用Jackson阻止Ebean中的Lazy加载?

时间:2015-02-04 12:48:13

标签: playframework jackson ebean

我有以下情况:

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有几种关系,它的关系本身也有依赖关系...... 我创建了一个功能,用户可以搜索Contrived Entities ....这个搜索功能不需要加载依赖项,但是当我使用play的帮助器Json.toJson序列化结果时,它会延迟加载其他依赖项,导致几个其他疑问......

我已设法通过使用Jackson Views(在最终结果中我想忽略的实体中使用注释)来阻止此行为... 但是我正在寻找可以在Ebean结束时完成的事情......同时撰写EBean查询......

以这种方式可以防止延迟加载吗? 如果回答“否”,那么Hibernate会提供这样的功能吗? 任何帮助都会非常感激... 如果您需要更多上下文,请留下评论,我将编辑问题。

非常感谢

5 个答案:

答案 0 :(得分:3)

我认为您可以使用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模块,但尚未发布。

将杰克逊的观点映射到Ebean&#39; pathProperties&#39;但我还没有看过那个。

希望这会有所帮助 干杯,罗布。

答案 1 :(得分:1)

  

...但是我正在寻找可以在Ebean结束时完成的事情......同时编写Ebean查询......

这是不可能的,很多人会喜欢这个功能(我2),唯一合理的方法是创建专用的模型类并使用所选数据“手动”填充它。

同样使用反射是一种很好的方法,特别是如果你有许多不同情况的高级REST api。

答案 2 :(得分:1)

只是添加一个额外的选择。 Ebean的查询现在还支持禁用延迟加载。

query.setDisableLazyLoading(true)

所以目前有3个选项:

  1. Query.setDisableLazyLoading(true)
  2. PathProperties
  3. avaje-ebeanorm杰克逊
  4. 我可能会喜欢第四种选择,但需要时间/精力。

答案 3 :(得分:0)

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

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

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

感谢您的帮助

答案 4 :(得分:0)

我需要一个解决方案,以避免在Json.toJson序列化期间ebean延迟加载并想出了这个。它非常多毛,但它具有本地化到模型类的优点,并且可以与标准的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模型类中,使用它:

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