我是新手使用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 });
}
}
答案 0 :(得分:5)
您必须详细了解JPA
:)
一旦实体在Persistence Context
中,它就会被JPA提供者跟踪,直到持久化上下文生命结束或调用EntityManager#detach()
方法。当事务完成(提交)时 - 持久化上下文中的托管实体的状态与数据库同步并进行所有更改。
如果您的实体是新实体,则可以通过调用EntityManager#persist()
方法将其置于持久化上下文中。
在您的情况下(更新现有实体),您必须从数据库中获取一行,并以某种方式将其更改为实体。它可以通过多种方式完成,但最简单的方法是调用将返回被管实体的EntityManager#find()
方法。返回的对象也将被置于当前的持久化上下文中,因此如果存在活动事务,您可以更改您喜欢的任何属性(而不是主键),并通过调用commit来完成事务(或者如果这是容器管理的事务,则只需完成方法)。
<强>更新强>
在您发表评论后,我可以看到您的观点。我认为您应该重新设计您的应用程序以符合JPA标准和功能。无论如何 - 如果你已经有了<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中提供了更新标准查询。
Here您可以找到有关元模型生成的更多信息。
除了元模型,你可以使用java反射机制。
答案 1 :(得分:1)
JPA处理更新。使用entitymanager将数据集作为实体检索,更改值并调用persist。这会将更改的数据存储在您的数据库中。
答案 2 :(得分:0)
如果你正在使用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文档确实是详细的资源。
从设计的角度来看,如果你有网络接口,我倾向于说包括一个服务委托层(PersonDelegateService eg),它将从UI接收的实际数据映射到人实体(反之,用于显示,填充查看来自人员实体的对象)并委托服务进行实际人员实体处理。