【问题标题】:Update multiple fields of JPA Entity更新 JPA 实体的多个字段
【发布时间】:2018-08-24 14:24:48
【问题描述】:

我的 JPA 实体客户有 50 个字段,我想使用 html 表单从最终用户那里更新它。

我将一个实体实例传递给 html 页面表单(使用 thymeleaf),该表单只有 50 个字段中的 20 个(包括 ID 字段)。现在,一旦提交了表单,我想将使用表单接收到的数据中的 20 个字段更新到数据库。我没有得到上述问题的解决方案。一种解决方案是更新单个字段,但我认为这不是一个好的解决方案。

@Entity
public class Customer
{
 ...
50 fields
}

我的get方法:

@GetMapping(value = "customer")
    public String customer(Model model) {
          Customer customer = null;
        Optional<Customer> optional = customer Repo.findById(customerId);

        if (optional.isPresent()) {
            customer = optional.get();
        }
        model.addAttribute("customer", Customer);
        return "customer";
    }

HTML 格式:

  <form action="updateCustomer">
    ----20 fields which I would like to get update from user are here
    </form>



@PostMapping(value = "updateCustomer")
public String updateCustomer(Model model, @ModelAttribute Customer customer) {
    if(customer==null) {
        System.out.println("Customer object is null");
    }
    else
    {
        customerRepo.save(customer);
    }
    return "savedCustomer";

}

在 post 方法中,当我获取客户对象时,它只有 20 个字段数据而不是 50 个(客户实体有总字段),因为 html 表单只有 20 个字段需要更新。如何使用更新了 20 个字段的新客户对象更新具有 50 个字段的旧客户对象?

【问题讨论】:

  • 这里没有足够的信息来帮助我不认为。除了代码繁琐之外,更新字段有什么问题?他们得到什么类型的值(来自其他数据或静态)?。
  • @CollinD 问题中提供了更多详细信息。请看一看。
  • 所以,澄清一下,你想基本上从数据库中获取一个Customer,并用你的表单中的数据覆盖它的20个字段(即:左合并你的新@ModelAttribute Customer),并且然后保存?
  • @CollinD 是的。你说的对。调用单个字段的 20 个设置器的基本方法。但我认为可能有更好的解决方案。
  • 在这种情况下,请查看stackoverflow.com/questions/24865923/… 在 Spring 的 BeanUtils 类中有一些内置功能可以管理这个。我不能说它的可定制性和安全性如何,但它很可能是可能的。但是,如果这只是为了节省一些输入,那么可能值得考虑跳过增加的复杂性。

标签: spring spring-mvc jpa spring-data-jpa


【解决方案1】:

过去我用三种方法解决了这个问题

1) 让页面获取相关的客户对象,使用该对象预填充表单,然后发布更改的客户对象。好处是更改客户的用户可以看到与客户相关的所有信息,并且您可以在后端轻松合并。缺点是额外的 REST 调用。

2) 创建一个 DTO,并将非空字段从 DTO 传输到实体。好处是您不必更新表单中的所有字段,也无需额外的网络调用。缺点是后端很痛苦。

3) 创建一个 DTO,并使其成为要保存的实体。好处是它很容易合并回数据库,没有什么能阻止您将相同的表和字段映射到多个实体。缺点是您必须担心并发问题,这可能在您的工作流程中不起作用,并且 DTO 基本上是每个表单特定的。

【讨论】:

    【解决方案2】:

    要对实体进行部分更新,您需要使用Criteria API 或JPQL 查询...这在JPA 中称为投影here is a quick example, 注意:如果您使用的是旧版本的 JPA 查询解析器(没有 JPQL 更新)+ 旧版本的 JPA(当没有 CriteriaUpdate 库时),您可能无法使用此功能,然后您需要获取来自客户端的 id 来自 DB 的对象,更新客户端的 20 个属性并保存更改

    【讨论】:

      【解决方案3】:

      以下解决方案对我有用:

      助手类:

      公共类 BeanCopy {

      private static final Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(
              Arrays.asList(Boolean.class, Character.class, Byte.class, Short.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class, String.class, Date.class));
      
      public static void nullAwareBeanCopy(Object dest, Object source) throws IllegalAccessException, InvocationTargetException
      {
          new BeanUtilsBean() {
              @Override
              public void copyProperty(Object dest, String name, Object value)
                      throws IllegalAccessException, InvocationTargetException {
                  if(value != null &&   (primitiveTypes.contains(value.getClass()) )) {
                      super.copyProperty(dest, name, value);
                  }
              }
          }.copyProperties(dest, source);
      }
      

      }

      这就是我复制并强制更改数据库的方式:

       try {
                  BeanCopy.nullAwareBeanCopy(DBcustomer,customer);
                  customerRepo.save(DBcustomer);
      
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              } catch (InvocationTargetException e) {
                  e.printStackTrace();
              }
      

      请告诉我以上问题有什么更好的解决方案。

      【讨论】:

      • 如果您这样做,如果您想通过将字段设置为 null 来将其清空怎么办?
      • @Vasan 我认为我们可以删除“不等于 null”条件,并将通过 http 请求接收到的字段数组来限制这些字段的更新,而不管它们的值如何。这个概念可行吗?
      猜你喜欢
      • 2018-09-04
      • 2011-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多