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

ddarikpa  于 12个月前  发布在  Spring
关注(0)|答案(3)|浏览(231)

我刚开始使用JPA,并试图将我的代码从JdbcTemplate转换到JPA。最初,我通过获取列及其值的Map来更新列的子集,并自己创建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 });
    }
}

字符串

5sxhfpxr

5sxhfpxr1#

一旦实体位于Persistence Context中,JPA提供程序将跟踪它,直到持久化上下文生命周期结束或调用EntityManager#detach()方法。当事务完成(提交)时-持久化上下文中托管实体的状态与数据库同步,并进行所有更改。
如果你的实体是新的,你可以简单地通过调用EntityManager#persist()方法把它放在persistence上下文中。
就您而言(更新现有实体),你必须从数据库中获取一行,并以某种方式将其更改为实体。这可以通过许多方式完成,但最简单的是调用EntityManager#find()方法,该方法将返回托管实体。返回的对象也将置于当前持久化上下文,因此如果有活动事务,你可以改变任何你喜欢的属性(不是主键),然后通过调用commit(或者如果这是容器管理的transaction,只需完成方法)来完成transaction。

更新

我认为你应该重新设计你的应用程序,以适应JPA标准和功能。无论如何-如果你已经有了一个对<Attribute_name, Attrbute_value>的Map,你可以使用一个叫做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();

字符串
请注意,JPA自2.1版本起提供了更新标准。
Here你可以找到更多关于元模型生成的信息。
除了元模型,你还可以使用java反射机制。

gtlvzcf8

gtlvzcf82#

JPA使用entitymanager将update.xml数据集处理为实体,更改值并调用persist。这将在数据库中存储更改的数据。

xxb16uws

xxb16uws3#

如果您使用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....
}

字符串

DAO

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

    ...
}

DaoImpl

@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文档确实是了解细节的好资源。
从设计的Angular 来看,如果你有Web接口,我倾向于说包括一个服务委托层(例如PersonDelegateService),它将从UI接收到的实际数据Map到person实体(反之亦然,为了显示,从person实体填充视图对象),并委托服务进行实际的person实体处理。

相关问题