2012-04-05 12 views
5

Tôi có một dự án GAE được viết bằng Java và tôi có một số suy nghĩ về HRD và một vấn đề mà tôi không chắc chắn cách giải quyết.Truy vấn HRD của Máy ứng dụng của Google mà không có tổ tiên

Về cơ bản tôi có người dùng trong hệ thống của mình. Người dùng bao gồm userid, tên người dùng, email và mật khẩu. Mỗi lần tôi tạo một người dùng mới, tôi muốn kiểm tra xem chưa có người dùng nào có cùng userid (không bao giờ xảy ra), tên người dùng hay email.

Userid là chìa khóa, vì vậy tôi nghĩ rằng việc thực hiện việc này sẽ nhất quán. Tuy nhiên, khi tôi thực hiện truy vấn (và sử dụng bộ lọc) để tìm người dùng có thể có cùng tên người dùng hoặc email, tôi không thể chắc chắn rằng kết quả là nhất quán. Vì vậy, nếu ai đó đã tạo một người dùng có cùng tên người dùng hoặc email một vài giây trước, tôi có thể không tìm thấy nó với truy vấn của tôi. Tôi hiểu rằng tổ tiên được sử dụng để giải quyết vấn đề này, nhưng nếu tôi không có tổ tiên để sử dụng cho truy vấn thì sao? Người dùng không có cha mẹ.

Tôi rất sẵn lòng nghe suy nghĩ của bạn về điều này và được coi là phương pháp hay nhất trong các tình huống như thế này. Tôi đang sử dụng Objectify cho GAE nếu điều đó thay đổi bất cứ điều gì.

+1

Tôi đã hỏi một câu hỏi mà bạn có thể thấy rất hữu ích. (http://stackoverflow.com/questions/6584435/how-can-i-create-two-unique-queriable-fields-for-a-gae-datastore-data-model) Tôi cũng cần lưu trữ thông tin duy nhất cho người dùng của tôi. Trong trường hợp của tôi, tôi cần lưu trữ cả một email duy nhất và User ID duy nhất cho mỗi người dùng. Đây là một chút khó khăn với HRD, nhưng tôi đã đi đến một giải pháp đáng tin cậy. ... cont ... – RLH

+0

Vấn đề duy nhất với tình huống của tôi là triển khai tạo tài khoản của tôi (xem câu trả lời của tôi) sẽ không mở rộng tốt. Đó là OK trong hoàn cảnh của tôi vì ứng dụng GAE của tôi rất nhỏ và có một lượng nhỏ người dùng mới (1 hoặc 2 tháng). Ngoài ra, thông tin này bằng Python, nhưng mã đơn giản-- bạn sẽ có thể quay lại -translate nó đến Java với tương đối dễ dàng. – RLH

+0

@RLH Cảm ơn bạn đã đầu vào, luôn thú vị để xem các giải pháp khác nhau, nhưng tôi không nghĩ rằng giải pháp của bạn sẽ hoạt động tốt trong trường hợp của tôi. – Joel

Trả lời

7

Tôi sẽ không khuyên bạn sử dụng email hoặc bất kỳ khóa tự nhiên nào khác cho thực thể Người dùng của bạn. Người dùng thay đổi địa chỉ email của họ và bạn không muốn kết thúc viết lại tất cả các tham chiếu khóa ngoài trong cơ sở dữ liệu của bạn bất cứ khi nào ai đó thay đổi email của họ.

Dưới đây là một lời giới thiệu ngắn về cách tôi giải quyết vấn đề này:

https://groups.google.com/d/msg/google-appengine/NdUAY0crVjg/3fJX3Gn3cOYJ

Tạo một thực thể EmailLookup riêng biệt mà @ id là hình thức bình thường của một địa chỉ email (Tôi chỉ chữ thường tất cả mọi thứ - không chính xác về mặt kỹ thuật nhưng tiết kiệm rất nhiều nỗi đau khi người dùng vô tình tận dụng [email protected]). EmailLookup của tôi trông như thế này:

@Entity(name="Email") 
public class EmailLookup { 
    /** Use this method to normalize email addresses for lookup */ 
    public static String normalize(String email) { 
     return email.toLowerCase(); 
    } 

    @Id String email; 
    @Index long personId; 

    public EmailLookup(String email, long personId) { 
     this.email = normalize(email); 
     this.personId = personId; 
    } 
} 

Ngoài ra còn có một (không-bình thường) trường email trong thực thể tài của tôi, mà tôi sử dụng khi gửi email đi (bảo vệ trường hợp chỉ trong trường hợp nó quan trọng đối với một người nào đó). Khi ai đó tạo tài khoản với một email cụ thể, tôi tải/tạo EmailLookup và các thực thể Người dùng theo khóa trong giao dịch XG. Điều này đảm bảo rằng mọi địa chỉ email cá nhân sẽ là duy nhất.

Chiến lược tương tự áp dụng cho bất kỳ loại giá trị duy nhất nào khác; id facebook, tên người dùng, v.v.

+1

Tôi có thể xác minh cho phương thức này. Tôi khuyên bạn nên sử dụng các id tự động tạo cho các thực thể "thực tế" và id chuỗi cho các tính năng thống nhất/truy vấn như thế này –

+0

Có các khóa tự nhiên hoàn toàn hợp pháp để sử dụng trong nhiều ứng dụng và sử dụng chúng thường có thể tiết kiệm được nhu cầu để thực hiện các truy vấn, ủng hộ kho dữ liệu hiệu quả hơn nhiều. Ví dụ, khóa tự nhiên của thực thể 'page' là URI của nó. –

+1

Chắc chắn, có rất nhiều thực thể mà một chìa khóa tự nhiên có ý nghĩa. Tôi chỉ yêu cầu rằng thực thể người dùng của OP không phải là một trong số họ :-) – stickfigure

3

Cách xung quanh eventual consistency của HRD, là sử dụng get thay vì query. Để có thể thực hiện việc này, bạn cần phải tạo ID tự nhiên, ví dụ: tạo ID bao gồm dữ liệu bạn nhận được theo yêu cầu: email và tên người dùng.

get trong HRD có tính nhất quán cao, bạn sẽ có thể kiểm tra đáng tin cậy nếu người dùng đã tồn tại.

Ví dụ một ID tự nhiên có thể đọc được sẽ là:

String naturalUserId = userEmail + "-" + userName; 

Lưu ý: trong thực tế email là duy nhất. Vì vậy, đây là một ID tự nhiên tốt trên riêng của nó. Không cần thêm tên người dùng đã tạo.

+1

Tôi thích sự đơn giản của giải pháp này, nhưng tôi không thích ý tưởng phải thay đổi khóa nếu email hoặc tên người dùng thay đổi. – Joel

-1

Bạn cũng có thể bật các giao dịch nhóm chéo (xem https://developers.google.com/appengine/docs/java/datastore/overview#Cross_Group_Transactions) và sau đó trong một giao dịch, hãy tìm người dùng và tạo một giao dịch mới, nếu điều đó có ích.

+1

Từ tài liệu đó: "Tương tự như giao dịch nhóm đơn, bạn không thể thực hiện truy vấn không phải tổ tiên trong giao dịch XG." –

+0

Vâng, vậy thì có vấn đề. Có thể thử truy vấn trước khi giao dịch, quá trình lưu, và sau đó bên ngoài giao dịch thực hiện một truy vấn khác để kiểm tra xem chỉ có một kết quả của loại mong muốn? Phải tốn nhiều thời gian hơn cho CPU, loại kiểm tra kép này, khi không có khả năng mọi người sẽ điền vào cùng một địa chỉ email. Ngoài ra, giải pháp này có vẻ khá ổn: http://stackoverflow.com/a/10032511/473180 – themarketka

+0

Ngoài ra, kiểm tra kép cũng không được đảm bảo để phù hợp, vì vậy bạn vẫn có thể có bản sao mà không biết. Về cơ bản, các truy vấn không phải tổ tiên không bao giờ có thể được sử dụng để kiểm tra tính nhất quán với HRD. –

-1

Đề xuất tránh trường được lập chỉ mục và truy vấn trừ khi bạn có các mục đích sử dụng khác cho nó. Đây là những gì tôi đã làm trước (Python) bằng cách sử dụng key_name (kể từ khi id thực thể cần phải được ints). Dễ sử dụng hoặc key_name hoặc id cho các thực thể khác cần liên kết đến người dùng:

username = self.request.get('username') 
usernameLower = username.lower() 
rec = user.get_by_key_name(usernameLower) 
if rec is None: 
    U = user(
     key_name = usernameLower, 
     username = username, 
     etc...) 
    U.put() 
else: 
    self.response.out.write(yourMessageHere) 
+0

Điều này không hoạt động khi người dùng khác có thể chèn tên người dùng bản ghi mới == usernameLower ngay trước khi đặt. – supercobra