Objectify - 如何@Load a List <ref <?>&gt;?</ref <?>

时间:2012-11-11 19:35:53

标签: google-app-engine objectify

我有一个实体,其中一个字段包含Refs到其他实体的列表(总是4)。我正在尝试获取一些实体,并将它们分配给jsp进行显示。我希望加载字段中的所有Refs,并在jsp中访问它们。

这是我的基本结构:

@Entity
public class Question {
    @Id Long id;
    @Index String question;
    @Load List<Ref<Answer>> answers = new ArrayList<Ref<Answer>>();
}

当我提取这样的问题时,显然jsp中存在错误。有道理,因为答案字段不是答案列表,而是refs:

ObjectifyService.register(Question.class);
ObjectifyService.register(Answer.class);

List<Question> questions = ofy().load().type(Question.class).limit(50).list();

req.setAttribute("questions", questions);
try { 
    getServletContext().getRequestDispatcher("/admin/view-questions.jsp").forward(req, resp); 
} catch (ServletException e) {
    System.out.println (e.getMessage());
}

那么如何在jsp中访问答案呢?是手动循环问题并为答案字段执行get()的唯一方法吗?

3 个答案:

答案 0 :(得分:8)

您可能会发现这个方便:

public class Deref {
    public static class Func<T> implements Function<Ref<T>, T> {
        public static Func<Object> INSTANCE = new Func<Object>();

        @Override
        public T apply(Ref<T> ref) {
            return deref(ref);
        }
    }

    public static <T> T deref(Ref<T> ref) {
        return ref == null ? null : ref.get();
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> List<T> deref(List<Ref<T>> reflist) {
        return Lists.transform(reflist, (Func)Func.INSTANCE);
    }
}

使用此方法,您可以提供以下方法:

@Entity
public class Question {
    @Id Long id;
    @Index String question;
    @Load List<Ref<Answer>> answers = new ArrayList<Ref<Answer>>();
    public List<Answer> getAnswers() { return Deref.deref(answers); }
}

有一点需要注意,它是一个只读列表。通过一点创造力,您可以创建可写的列表,但它需要创建一个ReversibleFunction和一个新的List.transform()方法。如果你只想要一些简单的JSP,你可能不想担心它。

或者,您可以在大多数表达语言中使用Ref的'value'属性。

答案 1 :(得分:7)

这样的事情怎么样:

@Entity
public class Question {
    @Id Long id;
    @Index String question;
    @Load List<Ref<Answer>> answers = new ArrayList<Ref<Answer>>();

    public List<Answer> loadAnswers()
    {
        return new ArrayList<Answer>(ofy().load().refs(answers).values());
    }
}

由于您已经使用@Load注释加载了实体,我认为客观化只会将它们从会话缓存中拉出来(它们不会被加载2次)。

如果您没有使用@Load注释,那么此方法将执行批量加载,这可能比循环遍历Refs并单独调用get()更好。

答案 2 :(得分:-1)

如果更改列表类型会怎样?

@Entity
public class Question {
    @Id Long id;
    @Index String question;
    @Load List<Answer> answers = new ArrayList<Answer>();
}

我检查一下,一切顺利,但在文档(https://code.google.com/p/objectify-appengine/wiki/Entities#Ref _ s)中没有任何对此案例的引用。

这样做是否安全?