我试图了解Wicket LoadableDetachable模型是如何工作的。 我从Wicket文档中理解的是在正常情况下,当请求完成时,处理窗口将自动序列化具有关联模型值的所有组件。这个将消耗更多的内存。如果我们在序列化时使用LoadableDetachable模型,则不会序列化模型值。这是正确的吗? 。因此它会自动分离模型对象。那么对于下一个请求,模型值将自动重新加载?请参阅下面的代码。
public class ProductListPanel extends Column<Product> {
@SpringBean
private ProductService productService;
private List productList;
public ProductListPanel(String id) {
super(id);
class ProductModel extends LoadableDetachableModel {
@Override
public void detach() {
// TODO Auto-generated method stub
productList = null;
System.out.print("Called Detach Object\n");
}
@Override
protected Object load() {
// TODO Auto-generated method stub
productList = productService.findAll();
System.out.print("Called Get Object\n");
return productList;
}
}
System.out.print("Before creating also calling\n");
final ProductModel productModel = new ProductModel();
ListView view = new ListView("list", productModel) {
protected void populateItem(ListItem item) {
System.out.print("\nBefore start also calling\n");
System.out.print("Before this one is callling \n");
Product result = (Product) item.getModelObject();
item.add(new Label("code", result.getCode()));
item.add(new Label("name", result.getName()));
final Link deleteLink = new Link("remove", item.getModel()) {
@Override
public void onClick() {
Product product = (Product) getModelObject();
productService.delete(product);
}
};
item.add(deleteLink);
}
};
add(view);
Link addProductLink = new Link("addProduct") {
@Override
public void onClick() {
// TODO Auto-generated method stub
setResponsePage(new AddProduct());
}
};
add(addProductLink);
productModel.detach();
}
}
在上面的代码中,我列出了数据库中的所有产品。我正在为每个产品删除链接,当我们点击该链接时,我将从数据库中删除产品。单击“删除”链接后,页面未刷新意味着它仍显示已删除的产品。如果我添加此行productModel.detach();然后它正常工作。我的问题是为什么我必须调用productModel.detach();手动? LoadableDetachableModel假设自动做对了吗?
请帮帮我
答案 0 :(得分:7)
LoadableDetachableModel
将检索到的对象缓存在其附加的持续时间内。当您load
数据库中的数据时,所有项目都在那里。然后执行查询以删除记录,但不要更新列表。因此,您必须将onClick
处理程序更改为还更新检索到的列表,或者只是分离模型。
LoadableDetachableModel中没有任何魔力。看看下面的代码:
List<Person> people = dao.getListOfPeopleAttendingParty();
// assume that the number of people attending the party is 4
assert people.size() == 4;
Person guest = people.get(0);
dao.delete(guest);
// what is the number of people attending the party now?
assert people.size() == ?;
您认为people.size()
现在是什么?
LoadableDetachableModel的执行与上面的代码片段没有任何不同:
List<Person> people = peopleModel.getObject(); // is called by ListView
// assume that the number of people attending the party is 4
assert people.size() == 4;
Person guest = people.get(0);
dao.delete(guest);
// what is the number of people attending the party now?
assert people.size() == ?;
所以:没有魔法,只是普通的Java和普通的逻辑。
PS。 这两个问题的答案是 4 ,即使数据库不再保留来宾
答案 1 :(得分:4)
这个主题很广泛。 LoadableDetachableModel非常适合对数据进行读取访问,因为您可以获得每次请求仅遍历加载方法一次的优势。但是,根据您想要达到的目标,这可能还不够。
由于LoadableDetachableModel在请求期间将一次加载的值存储在成员变量中,因此可能看不到对同一请求中发生的基础数据的更新。这是否是一个问题当然取决于所涉及的模型实例上调用getObject的时间。实际上这应该是一个相当罕见的问题。
我认为首先需要考虑组件结构和涉及的模型实例。可能有几种可能的设计来实现同样的目标。
根据组件结构的外观以及创建和分配给组件的模型实例的数量,请求中可能有多个特定模型的实例。此外,如果页面序列化被激活,那么以某种方式粘附到其模型实例的组件可能会以模型的其他实例结束,如果是LoadableDetachableModels,则可能在以后的请求中成为问题。
在我看来,将模型实例注入到组件的构造函数中是一种很好的做法,并确保只有真正需要的模型实例。获取在构造函数中传递的模型实例的组件,但不需要自己,只需将其委托给一个或多个相关子组件的构造函数。使用IModel类型参数在构造函数中非常清楚地定义组件的API。唯一的缺点可能是组件的用户需要根据正在发生的事情传递许多模型。当然,即使在这种模式中,模型也可以包装在装饰器中以用于任何目的。
出于某些目的,LoadableDetachableModel可能还不够,即应考虑具有更多功能的解决方案,例如在执行实际加载之前查看缓存的CachedModel。
在真正复杂的组件相互作用情况或请求处理情况中,可以考虑在自己专用的LoadableDetachableModel类中为LoadableDetachableModel实现重置机制。可以将带时间戳的重置令牌发布到请求范围,以通知其他已寻址的模型实例,它们必须丢弃其成员变量值,并在调用其getObject方法时再次遍历load方法。每个模型实例应该每个请求只兑换一个令牌,而每个请求可以发出多个令牌。
或者考虑没有缓存层来访问数据的情况,因此您需要在前端层中进行复杂的缓存。可以考虑将CachedModel实现为LoadableDetachableModel的特化 - 即它有三个位置来查找getObject中的模型值,成员变量,然后是缓存,最后是load方法 - 附加功能来发布带时间戳的重置令牌进入请求范围以通知已解决的CachedModel他们必须在返回任何内容之前丢弃其成员变量值。这个额外的重置功能可以确保在更新值后,相关的CachedModel实例将丢弃它们可能存储的成员变量值,并查看中央缓存。
当然还有其他方法可以通过模型实现某些功能。这取决于您想要做什么,设计以及页面中有多少组件需要在哪个时间点使用相关数据。