我是spring + hibernate的新手。当我添加客户及其目的地(一对多关系)时,一切都很好。但是当我更新客户的目的地时,所有以前的目的地都使用空的客户外键保留在数据库中。
假设我插入4个目的地a,b,c,d。更新客户后,我插入x,y。然后它存储了总共6个目的地:a,b,c,d带有空引用,x,y带有客户引用。
这是我的代码:
1)。客户实体
与目的地和关系的一对多关系是单向的。
@Entity
@Table(name="customers")
@Proxy(lazy=false)
public class CustomerEntity {
@Id
@Column(name="id")
@GeneratedValue
private Integer id;
private String description;
private String panNo;
private String cstNo;
private String vatNo;
@OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
@JoinColumn(name = "customer_id", referencedColumnName = "id")
public List<DestinationsEntity> destination = new AutoPopulatingList<DestinationsEntity>(DestinationsEntity.class);
//getter and setters
}
2)。目的地实体
@Entity
@Table(name = "destinations")
@Proxy(lazy = false)
public class DestinationsEntity {
@Id
@Column(name = "id")
@GeneratedValue
private Integer id;
@Column(name="destination")
private String destination;
// getter and setter
}
1)。 AddCustomer.jsp
此代码用于在自动填充列表中添加更多目的地
<div id="destination_container">
<div><textarea row="3" col="5" class="destination_address" name= "destination[${0}].destination" placeholder="Please enter address"></textarea></div>
</div>
<script type="text/javascript">
$(document).ready(function(){
var index = 1;
/*
* Add more destination
*/
$('#add_more_destination').click(function(){
$('#destination_container').append('<div><textarea row="3" col="5" class="destination_address" name= "destination[${"'+index+'"}].destination" placeholder="Please enter address"></textarea><span class="remove_dest">*</span></div>');
index++;
});
});
</script>
2)。 updateCustomer.jsp
客户添加的所有目的地都显示在此处,他/她可以更改目的地(如插入pune,mumbai,banglore之前),现在更新目的地(德里,旁遮普)
<c:set var="index" scope="page" value="${fn:length(destinationss)}"/>
<c:forEach items="${destinationss}" var="dest" varStatus="i">
<div>
<textarea class="destination_address" name= "destination[${i.index}].destination" placeholder="Please enter address">${dest.destination}</textarea><span class="remove_dest">*</span>
</div>
</c:forEach>
<button type ="button" id="add_more_destination">Add More Destinations</button>
<script type="text/javascript">
$(document).ready(function(){
/*
* Add a destination
*/
var index = ${index};
$('#add_more_destination').click(function(){
$('#destination_container').append('<div><textarea row="3" col="5" class="destination_address" name=destination["'+index+'"].destination placeholder="Please enter address"></textarea><span class="remove_dest">*</span></div>');
alert(index);
index++;
});
</script>
控制器
@RequestMapping(value = "/addCustomerForm", method = RequestMethod.GET)
public String addCustomerForm(ModelMap map) {
return "master/addCustomer";
}
@RequestMapping(value = "/addCustomer", method = RequestMethod.POST)
public String addCustomer(@ModelAttribute(value = "customer") CustomerEntity customer,BindingResult result, HttpServletRequest request) {
customerService.addCustomer(customer);
return "redirect:/customer";
}
更新客户
这是我昨晚尝试的新事物。问题部分解决了。
@ModelAttribute
public void updateOperation(HttpServletRequest request, ModelMap map) {
if(null !=request.getParameter("id"))
map.addAttribute("customer1", customerService.findOne(Integer.parseInt(request.getParameter("id"))));
}
@RequestMapping(value = "/updateCustomerForm/{customerId}", method = RequestMethod.GET)
public String updateCustomerForm(@PathVariable("customerId") Integer customerId, ModelMap map, HttpServletRequest request) {
CustomerEntity customerEntity = customerService.findOne(customerId);
map.addAttribute("customer", customerEntity);
map.addAttribute("destinationss",customerEntity.getDestination());
}
@RequestMapping(value = "/updateCustomer", method = RequestMethod.POST)
public String updateCustomer(@ModelAttribute(value = "customer1")CustomerEntity customer1,BindingResult result, HttpServletRequest request,HttpServletResponse response) {
customerService.updateCustomer(customer1);
return "redirect:/customer";
}
}
1)。 CustomerServiceImpl
public class CustomerServiceImpl implements CustomerService{
@Autowired
private CustomerDao customerDao;
@Override
@Transactional
public void addCustomer(CustomerEntity customer) {
customerDao.addCustomer(customer);
}
@Override
@Transactional
public CustomerEntity findOne(Integer id){
return customerDao.findOne(id);
}
@Override
@Transactional
public void updateCustomer(CustomerEntity customerEntity){
if (null != customerEntity) {
customerDao.updateCustomer(customerEntity);
}
}
}
2).CustomerDaoImpl
public class CustomerDaoImpl implements CustomerDao{
@Autowired
private SessionFactory sessionFactory;
@Override
@Transactional
public void addCustomer(CustomerEntity customer){
this.sessionFactory.getCurrentSession().save(customer);
}
@Override
public CustomerEntity findOne(Integer id){
return (CustomerEntity) sessionFactory.getCurrentSession().load(CustomerEntity.class, id);
}
@Override
@Transactional
public void updateCustomer(CustomerEntity customerEntity){
if (null != customerEntity) {
this.sessionFactory.getCurrentSession().update(customerEntity);
}
}
}
答案 0 :(得分:0)
问题是Spring会给你新的Customer实体,所以我猜这个Customer中的Destination实体最初是空的。因此,在您的更新操作中,您只需添加一些新的目标实体,然后根据您的代码将它们添加到客户。
因此,在这种情况下,客户实体只有新的目标对象,因为先前映射的现有目标实体不存在于您的客户实体中。
要解决此问题,首先从数据库获取Customer实体,然后此实体将具有一组Destination对象。现在,对于此客户,您可以添加新的Destination对象,并在需要时更新现有的Destination对象,然后请求Hibernate执行更新操作。在这种情况下,Hibernate可以看到您之前的目标对象以及新的目标对象,并且基于它将运行插入&amp;更新查询。
代码看起来像这样:
// First get the customer object from database:
Customer customer = (Customer) this.sessionFactory.getCurrentSession().get(Customer.class, customerId);
// Now add your destination objects, if you want you can update the existing destination entires here.
for (int i = 0; i < destinationAddrs.length; i++) {
DestinationsEntity destination = new DestinationsEntity();
destination.setDestination(destinationAddrs[i]);
customer.getDestinationEntity().add(destination);
}
// Then do the update operation
this.sessionFactory.getCurrentSession().update(customer);