RequestFactory 实体的参数:List<OfOtherEntity> 在客户端上为空。在服务器上没问题

RequestFactory Entity's parameter: List<OfOtherEntity> is null on client. On server is ok

我正在学习 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 */
}

这里是 DAO class Pizza 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;
}

共享包

我为那些 classes:

写了代理
@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();

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

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

的列表

发生这种情况是因为我没有 Ingredients 实体的 Dao 和定位器 classes 吗?

请帮忙。

回答: 实体关系

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

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

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

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

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

默认情况下,RequestFactory 不会递归地导致提取发生,以保存数据库调用和在线 space。

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

context.get().to(...

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

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

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

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

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

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