【问题标题】:PlayFramework 2.5 - Ebean update using reflectionPlayFramework 2.5 - 使用反射的 Ebean 更新
【发布时间】:2016-07-29 09:17:35
【问题描述】:


我正在使用 Play framework 2.5 和 Ebean 作为 ORM 开发一个带有内联编辑器的网站,并且我有一个新闻部分,管理员可以在其中编辑每条新闻(编辑标题、内容等内联字段)。
为了做到这一点,我将每个可以用 id 修改的 html 元素设置为新闻模型字段(例如,映射字段标题的 html 元素将具有 id="title"),然后当我从客户端接收数据时,我在控制器上使用反射将每个内容映射到正确的新闻字段。

代码如下(EditContent 是一个对象,其中包含每个修改内容的 id 和 htmlContent 等信息):

News news = News.find.byId(newsId);

for(EditContent content : pageContents.contents) {
    Field field = news.getClass().getField(content.cssId);
    field.setAccessible(true);
    field.set(news, content.htmlContent);
}

news.update();

问题是似乎执行了更新,但实际上没有在 db 上更新值。使用调试器,我检查了对象新闻,我可以看到字段已正确修改,但随后更新对 db 没有影响。
另外,我注意到使用相同的代码:

News news = new News()
...
//reflection to save modifed contents in the new object
...
news.save()

按我的预期工作,在数据库中保存一个新行。

有什么想法吗?

提前感谢您的帮助!

【问题讨论】:

  • 为什么需要使用反射?另外,当您更改 EditContent 对象时,您是否尝试保存它而不是新闻?
  • 我想使用反射以避免显式设置每个新闻字段(并编辑代码控制器以防我更改模型)。我无法保存 EditContent 因为它只是新闻字段的一个子集,特别是它只包含修改的字段,还包含与 html 相关的其他信息,例如 cssId
  • 嗨@lbaggi,你是怎么解决这个问题的?甚至有可能使它与反射一起工作吗?非常感谢您的回复,因为我遇到了完全相同的问题。谢谢

标签: java reflection playframework orm ebean


【解决方案1】:

您正在设置字段值,而不是调用 setter 方法。

所以对于 update() ... Ebean 不知道哪些属性已更改 - 它认为没有任何更改。

Play 通过增强将字段 put 调用修改为方法调用。所以这可能就是您认为这些反射字段集值可能起作用的原因。

【讨论】:

  • 也就是说,没有办法使用反射来更新实体吗?我必须直接设置每个字段(并让 Ebean 处理其生成的 getter/setter)?为什么要插入新实体?
  • > 换句话说,没有办法使用反射来更新实体吗? ...不。意思是Ebean拦截方法(setter),你不能拦截反射字段集。
  • 您是否意识到 Ebean 需要 getter 和 setter(嗯,方法)。是 Play 促进了公共字段的使用……以及将这些公共字段 getfield/putfield 调用转换为方法调用的 Play 增强功能……是 Play 这样做,而不是 Ebean。
  • 您的新闻实体 bean 是否有方法或公共字段?我认为它有公共领域......因为 Play 已经推广了。
  • News 实体 bean 也将有方法(一些由 Play 添加 - 有效的 getter 和 setter,一些由 Ebean 增强)。如果你使用反射来调用那些 setter 方法...
【解决方案2】:

所以基本上,正如@Rob Bygrave 所说......应该在这里调用setter方法而不是直接设置字段值,因为如果您直接将值设置为相应的字段,ebean将忽略新值。看来play框架是遵循Java bean约定的,所以基本上我们可以猜到集合名称叫什么。 下面是一个动态更新用户信息的示例代码:

private final String[] userUpdatableNames = { "name", "password", "allowGPS" };

...

        JsonNode dateForm = request().body().asJson();
        Field field;
        Class<?> type;
        Method method;      
        for (int i = 0; i < userUpdatableNames.length; i++) {
            if (isArgs[i]) {
                        try {
                            field = target.getClass().getDeclaredField(userUpdatableNames[i]);
                            type = field.getType();
                            Method method = target.getClass().getMethod("set" + initialUpperize(userUpdatableNames[i]), type);
                            method.invoke(target, convert(type,dateForm.findValue(userUpdatableNames[i]).textValue()));
                            }catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException
| NoSuchMethodException | InvocationTargetException e) {
                            return internalServerError(Json.toJson("Invoke exception"));
                           }
            } 
      }

...

public String initialUpperize(String str) {
    return str.substring(0, 1).toUpperCase() + str.substring(1);
}

...

private Object convert(Class<?> targetType, String text) {
    PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
    editor.setAsText(text);
    return editor.getValue();
}

其中isArgs是一个布尔数组,用来标记该字段是否在Json body中...

谢谢

【讨论】:

    猜你喜欢
    • 2017-05-31
    • 2015-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多