6

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

这是我的基本结构:

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

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

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() 的唯一方法吗?

4

3 回答 3

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 的“值”属性。

于 2012-11-12T17:20:32.240 回答
8

像这样的东西怎么样:

@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 注释加载了实体,我认为 objectify 只会从会话缓存中提取它们(它们不会被加载 2 次)。

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

于 2015-02-09T15:57:34.650 回答
-1

如果更改 List 类型会发生什么?

@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)中没有任何关于这种情况的参考。

这样做安全吗?

于 2013-05-08T17:04:02.857 回答