繁体   English   中英

Spring JPA-更新多个字段的最佳方法

[英]Spring JPA - Best way to update multiple fields

我是使用JPA的新手,并尝试将我的代码从JdbcTemplate过渡到JPA。 最初,我通过获取列及其值的映射来更新列的子集,并亲自创建SQL Update字符串并使用DAO执行它。 我想知道使用JPA做类似事情的最佳方法是什么?

编辑:
如何将这段代码从DAO转换为JPA中的等效代码?

public void updateFields(String userId, Map<String, String> fields) {
    StringBuilder sb = new StringBuilder();
    for (Entry<String, String> entry : fields.entrySet()) {
        sb.append(entry.getKey());
        sb.append("='");
        sb.append(StringEscapeUtils.escapeEcmaScript(entry.getValue()));
        sb.append("', ");
    }

    String str = sb.toString();
    if (str.length() > 2) {
        str = str.substring(0, str.length() - 2); // remove ", "
        String sql = "UPDATE users_table SET " + str + " WHERE user_id=?";
        jdbcTemplate.update(sql, new Object[] { userId },
                new int[] { Types.VARCHAR });
    }
}

您必须确定要阅读有关JPA更多信息:)

实体进入Persistence Context ,JPA提供程序将对其进行跟踪,直到持久性上下文生存期结束或直到调用EntityManager#detach()方法为止。 当事务完成(提交)时,持久性上下文中的受管实体的状态将与数据库同步,并进行所有更改。

如果您的实体是新实体,则可以通过调用EntityManager#persist()方法将其置于持久性上下文中。

对于您的情况(现有实体的更新),您必须从数据库中获取一行并将其更改为实体。 它可以通过多种方式完成,但最简单的方法是调用EntityManager#find()方法,该方法将返回托管实体。 返回的对象也将置于当前的持久性上下文中,因此,如果有活动的事务,则可以更改所需的任何属性(而不是主键),并通过调用commit来完成事务(或者如果这是容器管理的事务,则为finish方法) )。

更新

在您发表评论后,我可以看到您的观点。 我认为您应该重新设计应用程序以适合JPA标准和功能。 无论如何-如果您已经有一对<Attribute_name, Attrbute_value>对的映射<Attribute_name, Attrbute_value>可以使用一个称为Metamodel的东西。 简单用法如下所示。 这是幼稚的实现,仅适用于基本属性,您应该注意关系等。(可以通过attr.getJavaType()attr.getPersistentAttributeType()方法来获取有关属性的更多信息)

Metamodel meta = entityManager.getMetamodel();
EntityType<User> user_ = meta.entity(User.class);

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaUpdate<User> update = cb.createCriteriaUpdate(User.class);

Root e = update.from(User.class);

for( Attribute<? super User, ?> attr : user_.getAttributes() ) {
      if (map.containsKey(attr.getName())) {
          update.set(attr, map.get(attr));
      }
}

update.where(cb.equal(e.get("id"), idOfUser));
entityManager.createQuery(update).executeUpdate();

请注意,自2.1版本开始,JPA中提供了更新条件查询。

在这里,您可以找到有关元模型生成的更多信息。

除了元模型,您还可以使用Java反射机制。

JPA处理更新。 使用entitymanager将数据集作为实体检索,更改值并调用持久化。 这会将更改的数据存储在您的数据库中。

如果您使用的是Hibernate(作为JPA提供程序),这是一个示例

实体

@Entity
@Table(name="PERSON")
public class Person {

    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    @Column(name="NAME", nullable=false)
    private String name;

    other fields....
}

public interface PersonDao  {
    Person findById(int id);    
    void persist(Person person);

    ...
}

道普

@Repository("personDao")
public class PersonDaoImpl extends AnAbstractClassWithSessionFactory implements PersonDao {

    public Person findById(int id) {
        return (Person) getSession().get(Person.class, id);
    }

    public void persist(Person person){
       getSession().persist(person);
    }
}

服务

@Service("personService")
@Transactional
public class PersonServiceImpl implements PersonService {

    @Autowired
    PersonDao personDao;

    @Override
    public void createAndPersist(SomeSourceObject object) {
      //create Person object and populates with the source object
      Person person = new Person();     
      person.name = object.name;
      ...
      personDao.persist(person);
    }

    @Override
    public Person findById(int id) {
        return personDao.findById(id);
    }

    public void doSomethingWithPerson(Person person) {
         person.setName(person.getName()+" HELLO "); 
    //here since we are in transaction, no need to explicitly call update/merge
    //it will be updated in db as soon as the methods completed successfully
    //OR
    //changes will be undone if transaction failed/rolledback
   }
}

对于详细信息,JPA文档确实是很好的资源。

从设计的角度来看,如果您具有Web接口,我倾向于说再包括一个服务委托层(例如,PersonDelegateService),它将从UI接收的实际数据映射到人实体(反之亦然,以进行显示)以填充视图对象。人员实体)并委托服务进行实际人员实体处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM