【问题标题】:RequestFactory Entity's parameter: List<OfOtherEntity> is null on client. On server is okRequestFactory 实体的参数:List<OfOtherEntity> 在客户端为空。服务器上没问题
【发布时间】:2015-11-24 05:36:30
【问题描述】:

我正在学习 RequestFactory。我有简单的示例工作。现在我想从下面为 RF 实施这些实体:


服务器包

@Entity
public class Pizza implements Identifiable, Versionable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Version
    private Long version;
    private String name;
    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Ingredient> ingredients;
    /* Getters and Setters */
}

@Entity
public class Ingredient implements Identifiable, Versionable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Version
    private Long version;
    private String name;
    private boolean vegan;
    /* Getters and Setters */
}

这是DAOPizza Entity 类:

@Override
public List<Pizza> get() {

    CriteriaBuilder cb = JPA.em().getCriteriaBuilder();
    CriteriaQuery<Pizza> q = cb.createQuery(Pizza.class);
    Root<Pizza> c = q.from(Pizza.class);
    q.select(c);

    TypedQuery<Pizza> query = JPA.em().createQuery(q);
    List<Pizza> results = query.getResultList();

    for(Pizza p: results) {
        for(Ingredient i: p.getIngredients()) {
            logger.info(i.getName());
        }
    }
    return results;
}

共享包

我为这些类编写了代理:

@ProxyFor(value = Pizza.class, locator = PizzaLocator.class)
public interface PizzaProxy extends EntityProxy {
  public Long getId();
  public String getName();
  public void setName( String name );
  public Long getVersion();
  public List<IngredientProxy> getIngredients();
  public void setIngredients( List<IngredientProxy> ingredients )
}

@ProxyFor(value = Ingredient.class)
public interface IngredientProxy extends EntityProxy {
    public void setId(Long id);
    public Long getId();
    public Long getVersion();
    public void setVersion(Long version);
    public String getName();
    public void setName(String name);
    public boolean isVegan();
    public void setVegan(boolean vegan);
}

射频相关接口:

public interface RequestFactoryServices extends RequestFactory {
      PizzaRequest pizzaRequest();
}

@Service(value = PizzaDao.class, locator = DaoLocator.class)
public interface PizzaRequest extends RequestContext {
    Request<PizzaProxy> findById( Long id );
    Request<Void> save( PizzaProxy pizza );
    Request<List<PizzaProxy>> get();
}

客户端包

这是我从服务器获取数据的方式:

List<PizzaProxy> pizzas = new LinkedList<PizzaProxy>();
PizzaRequest context = createFactory().pizzaRequest();
context.get().to(new Receiver<List<PizzaProxy>>() {
        @Override
        public void onSuccess(List<PizzaProxy> response) {
            for(PizzaProxy p: response) {
                RootPanel.get().add(new Label(
                    p.getId() + " " + 
                    p.getName() + ", " + 
                    p.getVersion() + ", " + 
                    p.getIngredients()
                 ));
            }
        }
    }).fire();

正如您在get() 方法中的DAO 类中所见,我正在打印以记录有关成分的信息。在服务器端一切正常。

问题是当我调用p.getIngredients() 时,我得到的是null,而不是IngredientsProxies 的列表。

这是因为我没有 Ingredients Entity 的 Dao 和 Locator 类吗?

请帮忙。

回答: 实体关系

对相关实体的更改可以保存在单个请求中。例如,GWT trunk 中 DynatableRF 示例应用程序中的这段代码同时创建了一个新的 Person 和 Address:

PersonRequest 上下文 = requestFactory.personRequest(); AddressProxy 地址 = context.create(AddressProxy.class); PersonProxy person = context.create(PersonProxy.class); person.setAddress(地址); context.persist().using(person).fire(...); RequestFactory 在单个请求中自动发送整个对象图。在这种情况下,服务器上 Person.persist() 的实现也负责持久化相关的地址,这可能会或可能不会自动发生,具体取决于 ORM 框架和关系的定义方式。请注意,RequestFactory 目前不支持嵌入对象(各种 ORM 框架中的 @Embedded),因为它希望每个实体都以自己的 ID 独立存在。

查询服务器时,RequestFactory 不会自动填充对象图中的关系。为此,请在请求上使用 with() 方法并将相关属性名称指定为字符串:

请求 findReq = requestFactory.personRequest().find(personId).with("address"); 还需要使用 with() 方法来检索具有扩展 ValueProxy 类型的任何属性。 with() 方法接受多个 String 参数,因此您可以一次指定多个属性名称。要指定嵌套属性,请使用点表示法。综上所述,你可能有

请求 findReq = find(personId).with("phone","address.city","address.zip")

【问题讨论】:

    标签: java gwt requestfactory


    【解决方案1】:

    默认情况下,RequestFactory 不会递归地导致提取发生,以节省数据库调用和网络空间。

    如果您需要 ingredients 属性,则必须请求它。而不是

    context.get().to(...
    

    在其中添加对Request.with(String... propertyRefs) 的调用,并指定您想要的成分:

    context.get().with("ingredients").to(...
    

    没有Ingredients 类型的定位器可能最终很重要,但是如果您尝试以需要Locator 或类中的静态方法的方式使用这些对象,则会遇到特定错误.你不需要一个特定的 DAO 和 ServiceLocator 类,除非你最终为它创建了一个 RequestContext 类型。

    【讨论】:

    • “成分”可以通过某种方式保存吗?我想尽可能避免使用字符串 :-)
    【解决方案2】:

    默认情况下,gwt 在获取对象时不附加集合实体。您需要在您的 rf 请求中使用 .with("ingredients") 。确保你的披萨类中有一个 getIngredients 方法。 rf 请求上下文将使用它来获取成分。如果您从 hibernate 之类的东西中获取它,您可能还需要确保您有一个打开的事务。这将确保 rf 上下文在检索比萨饼的成分时可以使用附加的实体。

    请注意,您不想使用 with("getIngredients") rf 上下文将正确调用 get 方法。

    context.get().with("ingredients").fire(new Receiver<>)
    

    【讨论】:

    • “成分”可以通过某种方式保存吗?我想尽可能避免使用字符串 :-)
    • 我也有同样的感觉,实际上提出了一种增强功能,将@Eager 注解支持添加到 Proxy 类中,以便识别应该急切获取的集合。我实际上可能会在某个时候自己做这件事,但已经改用 GWT-RESTY,这样我的 api 就更便携了。我在代理中创建了常量作为助手,这样我就可以使用 with(PizzaProxy.Ingredients) 之类的东西,而不必使用字符串并在多个地方进行更改。请记住,默认情况下不发送集合会显着提高性能。
    • 也可以通过反射或代码生成来完成。必须等待 Google 实施。
    • 由于编译代码中缺少反射,无法有效地进行反射。很可能它必须在请求工厂延迟绑定处理程序中实现。
    • 粗略一看,您可以修改这个解析器类来解释注释。我不记得它是否可以访问该界面,但这可能有效。您必须替换服务器端的类才能使其正常工作。检查处理属性参考的部分。 github.com/gwtproject/gwt/blob/…
    猜你喜欢
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-30
    • 2011-06-06
    相关资源
    最近更新 更多