2015-01-07 20 views
28

Có cách nào để cập nhật chỉ một số lĩnh vực của một đối tượng thực thể sử dụng phương pháp save từ liệu mùa xuân JPA?JPA: chỉ cập nhật các lĩnh vực cụ thể

Ví dụ tôi có một thực thể JPA như thế này:

@Entity 
public class User { 

    @Id 
    private Long id; 

    @NotNull 
    private String login; 

    @Id 
    private String name; 

    // getter/setter 
    // ... 
} 

Với repo CRUD của nó:

public interface UserRepository extends CrudRepository<User, Long> { } 

Trong Spring MVC Tôi có một bộ điều khiển nhận được một đối tượng User để cập nhật nó :

@RequestMapping(value = "/rest/user", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) 
@ResponseBody 
public ResponseEntity<?> updateUser(@RequestBody User user) { 

    // Assuming that user have its id and it is already stored in the database, 
    // and user.login is null since I don't want to change it, 
    // while user.name have the new value 

    // I would update only its name while the login value should keep the value 
    // in the database 
    userRepository.save(user); 

    // ... 
} 

Tôi biết điều đó Tôi có thể tải người dùng bằng cách sử dụng findOne, sau đó thay đổi tên của nó và cập nhật nó bằng cách sử dụng save ... Nhưng nếu tôi có 100 trường và tôi muốn cập nhật 50 trường, nó có thể thay đổi rất khó chịu mỗi giá trị ..

Có không có cách nào để nói một cái gì đó như "bỏ qua tất cả các giá trị null khi lưu đối tượng"?

+3

Không có. Cách chính xác duy nhất là truy xuất đối tượng, cập nhật các trường và lưu trữ nó và điều đó có thể là động. Nếu bạn muốn một cái gì đó khác, bạn sẽ phải viết SQL cho nó và làm điều đó cho mình. Nhưng giả sử 'User' chỉ có' ​​null' cho các trường bạn không muốn lưu những gì bạn có thể làm là theo cách khác, sử dụng 'User' và cập nhật các trường bạn biết chưa thay đổi, sau đó cập nhật cái đó. –

+0

Có một lý do tại sao tốt hơn là không bỏ qua các giá trị null đang cập nhật một đối tượng? – Andrea

+0

Không có cách nào đáng tin cậy để biết những gì để bỏ qua, null có thể là một lựa chọn hợp lệ cho các lĩnh vực, sau đó những gì? Bạn có lẽ có thể shoehorn một cái gì đó tại chỗ với ann 'EntityListener' hoặc một cái gì đó như thế, nhưng tôi sẽ khuyên bạn nên chống lại nó vì nó có thể sẽ dẫn đến nhiều vấn đề hơn nó giải quyết. –

Trả lời

1

sự cố không liên quan đến dữ liệu của luồng jpa mà là lib triển khai thực hiện mà bạn đang sử dụng có liên quan. Trong trường hợp ngủ đông bạn có thể có một cái nhìn tại địa chỉ:

http://www.mkyong.com/hibernate/hibernate-dynamic-update-attribute-example/

+0

Cảm ơn bạn đã tham khảo .. Thực ra tôi đang sử dụng chế độ ngủ đông. Trong bài viết đó được đề nghị thay đổi thuộc tính 'dynamic-update': Tôi đã cố gắng thực hiện nó bằng cách sử dụng chú thích nhưng thuộc tính đó không được hỗ trợ trong chú thích @Entity của JPA và chú thích @Entity của Hibernate không được chấp nhận .... Bạn có biết cách thích hợp để thiết lập nó? – Andrea

+0

Như được đề xuất trong câu trả lời khác, cách thực tế để thay đổi 'cập nhật động' đang sử dụng chú thích' @ DynamicUpdate' ... Tôi đã thử nhưng tôi không thấy bất kỳ thay đổi nào ... Bất kỳ đề xuất nào? – Andrea

23

Tôi có cùng một câu hỏi và như M. Deinum chỉ ra, câu trả lời là không, bạn có thể không sử dụng tiết kiệm. Vấn đề chính là Spring Data sẽ không biết phải làm gì với null. Giá trị null có được đặt hay không được đặt bởi vì nó cần được xóa?

Bây giờ đánh giá từ bạn câu hỏi, tôi giả sử bạn cũng có cùng suy nghĩ rằng tôi đã có, đó là lưu sẽ cho phép tôi tránh đặt thủ công tất cả các giá trị thay đổi.

Vì vậy, có thể tránh được tất cả ánh xạ manuel sau đó không? Vâng, nếu bạn chọn tuân theo quy ước, null luôn luôn có nghĩa là 'không được thiết lập' và bạn có id mô hình ban đầu, thì có. Bạn có thể tự mình tránh bản đồ bằng cách sử dụng Spring BeanUtils.

Bạn có thể làm như sau:

  1. Đọc đối tượng hiện
  2. Sử dụng BeanUtils để sao chép các giá trị
  3. Save the object

Bây giờ, BeanUtils Spring thực tế không hỗ trợ không sao chép giá trị null, vì vậy nó sẽ ghi đè lên bất kỳ giá trị nào không được đặt bằng null trên đối tượng mô hình thoát. May mắn thay, có một giải pháp ở đây:

How to ignore null values using springframework BeanUtils copyProperties?

Vì vậy, đặt nó tất cả cùng nhau bạn sẽ kết thúc với một cái gì đó như thế này

@RequestMapping(value = "/rest/user", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) 
@ResponseBody 
public ResponseEntity<?> updateUser(@RequestBody User user) { 

    User existing = userRepository.read(user.getId()); 
    copyNonNullProperties(user, existing); 
    userRepository.save(existing); 

    // ... 
} 

public static void copyNonNullProperties(Object src, Object target) { 
    BeanUtils.copyProperties(src, target, getNullPropertyNames(src)); 
} 

public static String[] getNullPropertyNames (Object source) { 
    final BeanWrapper src = new BeanWrapperImpl(source); 
    java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); 

    Set<String> emptyNames = new HashSet<String>(); 
    for(java.beans.PropertyDescriptor pd : pds) { 
     Object srcValue = src.getPropertyValue(pd.getName()); 
     if (srcValue == null) emptyNames.add(pd.getName()); 
    } 
    String[] result = new String[emptyNames.size()]; 
    return emptyNames.toArray(result); 
} 
+4

Tôi tin rằng nó nên là 'userRepository.save (hiện tại);' không '#save (người dùng);' – dbahdano

+0

Nhận xét trên làm việc cho tôi cảm ơn rất nhiều. –

+0

nếu datatype là số nguyên mặc định của nó là số không được cập nhật trong mysql. Làm việc tốt của nó cho chuỗi làm thế nào chúng ta có thể làm điều đó cho các kiểu dữ liệu khác như int, char, double. –

2

Sử dụng JPA bạn có thể làm theo cách này.

CriteriaBuilder builder = session.getCriteriaBuilder(); 
CriteriaUpdate<User> criteria = builder.createCriteriaUpdate(User.class); 
Root<User> root = criteria.from(User.class); 
criteria.set(root.get("lastSeen"), date); 
criteria.where(builder.equal(root.get("id"), user.getId())); 
session.createQuery(criteria).executeUpdate(); 
Các vấn đề liên quan