2014-06-05 14 views
5

Tôi có đối tượng tài khoản tham chiếu đến đối tượng người dùng.Xác định đối tượng tải sau Ref <?> ngay cả khi @Load không được chỉ định

@Cache 
@Entity 
public final class Account { 

    @Id Long id; 
    @Index private Ref<User> user; 

    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 

    public User getUser() { 
     return user.get(); 
    } 
    public void setUser(User user) { 
     this.user = Ref.create(user); 
    } 

} 

Tôi đã giấu những Ref theo khuyến cáo ở đây: http://code.google.com/p/objectify-appengine/wiki/Entities - xin lưu ý Ref làm không có chú thích @Load.

Khi tôi gọi Google Cloud Endpoint của mình từ máy khách Android, có vẻ như Objectify cung cấp đối tượng tài khoản với người dùng được nhúng, mặc dù @Load không được chỉ định.

@ApiMethod(name = "account.get") 
public Account getAccount(
     @Named("id") final Long id 
) { 
    return ofy().load().type(Account.class).id(id).now(); 
} 

Khi tôi truy vấn tài khoản trực tiếp sử dụng Apis Explorer, tôi cũng có được cả hai, chiếm với người sử dụng nhúng:

200 OK 
{ 
"id": "5079604133888000", 
"user": { "id": "5723348596162560", 
"version": "1402003195251", 
"firstName": "Karl" }, 
"kind": "api#accountItem", 
"etag": "\"30khohwUBSGWr00rYOZuF9f4BTE/Q31EvnQCQ6E9c5YXKEZHNsD_mlQ\""} 

Điều này đặt ra ba câu hỏi:

  1. Liệu AppEngine luôn trở lại nhúng Refs nguyên bản và Objectify luôn truyền vào các đối tượng mà nó đã biết chưa?
  2. Chính xác là gì @Load cho và có cách nào để kiểm soát hành vi này không? Tải nhóm?
  3. Tôi đã bỏ lỡ điều gì chưa? Tại sao @Load không tuân theo?

Trả lời

12

Trong mã ví dụ của bạn, bạn không chỉ định @Load có nghĩa là việc tải tài khoản sẽ không tìm nạp User. Tuy nhiên, @ApiMethod của bạn đang tuần tự hóa tài khoản trở lại máy khách, do đó, thuộc tính user được truy cập, do đó, tìm nạp riêng được cấp để tải đối tượng người dùng. Đó là lý do tại sao bạn nhận được thông tin của người dùng khi gọi phương thức.

Không chỉ định @Load không có nghĩa là bạn sẽ không nhận được khoản bồi hoàn User. Điều đó có nghĩa là bạn sẽ không truy xuất số User trừ khi bạn yêu cầu cụ thể sau này.

Ref làm việc như thế này:

  • tôi là một tài liệu tham khảo, vì vậy theo mặc định tôi sẽ không lấy dữ liệu.
  • Nếu bạn yêu cầu tôi, trước tiên tôi sẽ tải dữ liệu, sau đó trả lời bạn.
  • Ồ, nếu bạn tự cho tôi biết số @Load thì tôi sẽ tìm nạp dữ liệu ban đầu và chuẩn bị sẵn sàng cho bạn.

Vì vậy, điều này hoạt động tốt trong mã của bạn ... nhưng sau đó @ApiMethod của bạn đang tuần tự hóa đối tượng Account quay lại khách hàng. Quá trình tuần tự hóa đang trải qua mọi thuộc tính trong đối tượng Account của bạn, bao gồm thuộc tính user. Tại thời điểm này, các Ref<User> đang được truy cập, do đó, dữ liệu sẽ được lấy từ Datastore và sau đó quay trở lại khách hàng.

Điều này làm cho mã của bạn rất kém hiệu quả, vì các đối tượng Account được tải mà không có thông tin User, nhưng sau đó bạn luôn truy cập thông tin User sau này (trong quá trình tuần tự hóa), phát hành tìm nạp riêng.Batching gets từ Datastore là cách hiệu quả hơn việc phát hành riêng biệt gets.

Trong trường hợp của bạn, bạn có thể làm một trong hai điều:

  1. Thêm @Load đến tài sản của người dùng, vì vậy các đối tượng Account được nạp một cách hiệu quả.
  2. Làm cho @ApiMethod trả về một đối tượng Account khác nhau mà không có thuộc tính user (do đó tránh tìm nạp người dùng nếu bạn không cần).

Tùy chọn 2 ở trên khá hữu ích vì bạn có thể trừu tượng cấu trúc Datastore nội bộ của bạn từ những gì khách hàng nhìn thấy. Bạn sẽ thấy mình sử dụng patter này khá thường xuyên.

+2

Cảm ơn bạn @svpino vì câu trả lời rất chi tiết của bạn và tôi tin rằng điều này là rất quan trọng đối với tất cả những người đang sử dụng phản đối REST **. Nó không rõ ràng với tôi rằng mặc dù tôi không truy cập một cách rõ ràng Ref <> từ mã của tôi, serializer làm như vậy. –

+0

Điều gì xảy ra nếu tôi đặt rõ ràng đối tượng người dùng là null trước khi gửi cho khách hàng? – Dexter

Các vấn đề liên quan