2011-08-04 30 views
19

Tôi gặp vấn đề lạ.
Tôi có hai lớp miền UserPost với các lĩnh vực:Tại sao grails ném ngoại lệ con trỏ null trong khi truy cập mối quan hệ hasMany lần đầu tiên?

class User { 
    String name 
    static hasMany = [posts: Post] 
    static constraints = { } 
} 

class Post { 
    String content 
    long date = System.getTimeInMillis() 
    static constraints = { } 

    static belongsTo = [user: User] 
    static mapping = { 
    version: 'false' 
    } 
} 

và mã điều khiển là:

class UserController { 
    def addUser = { 
    def user 
    if (User.count() == 0) { 
     user = new User() 
     user.name = "Manish Zedwal" 
     user.save(flush: true) 
    } else { 
     user = User.get(1) 
    } 
    println "Posts count: " + user.posts.size() 
    render "post count: " + user.posts.size() 
} 
} 

Đối với lần đầu tiên khi truy cập url http://localhost:8080/test/user/addUser, nó ném ngoại lệ con trỏ null, nhưng sau khi nó hoạt động tốt.
Đây là ngoại lệ Tôi nhận

2011-08-04 15:41:25,847 [http-8080-1] ERROR errors.GrailsExceptionResolver - Exception occurred when processing request: [GET] /test/user/addUser 
Stacktrace follows: 
java.lang.NullPointerException: Cannot invoke method size() on null object 
     at test.UserController$_closure2.doCall(UserController.groovy:18) 
     at test.UserController$_closure2.doCall(UserController.groovy) 
     at java.lang.Thread.run(Thread.java:636) 

và lần thứ hai, nó in và ám tốt như quyến rũ

Posts count: 0 

Trong lớp người sử dụng tên miền, coz của hasMany mối quan hệ cho posts, posts là một danh sách các đối tượng Post sau đó không nên có ngoại lệ con trỏ null trên nhận được kích thước của danh sách trống, thay vì nó phải bằng không.

Bất kỳ giúp đánh giá cao

Trả lời

29

Khi bạn ánh xạ một bộ sưu tập như vậy, việc kê khai hasMany bổ sung thêm một lĩnh vực loại Set với tên được chỉ định (trong trường hợp này posts) để lớp học của bạn. Nó không khởi tạo các thiết lập mặc dù, do đó, nó ban đầu null. Khi bạn gọi addToPosts, nó sẽ kiểm tra nếu nó rỗng và tạo một Tập trống mới nếu cần và thêm Bài đăng vào bộ sưu tập. Nhưng nếu bạn không gọi addToPosts hoặc khởi tạo rõ ràng tập hợp, nó sẽ là rỗng.

Khi bạn tải User từ cơ sở dữ liệu, Hibernate sẽ điền tất cả các trường và bộ sưu tập được bao gồm trong đó. Nó tạo ra một Set mới (một sửa đổi-nhận thức PersistentSet) đó là sản phẩm nào, và thêm trường hợp cho nó nếu có bất kỳ. Gọi số save() không tải lại cá thể từ cơ sở dữ liệu, do đó, tập null sẽ vẫn là rỗng.

Để có được lớp để hành xử theo cách tương tự khi nó mới và khi nó dai dẳng, bạn có thể thêm một trường để lớp học của bạn Giống như Rob cho thấy trong câu trả lời của mình, khởi tạo một tập rỗng (Set posts = [])

+0

Cảm ơn Beckwith –

11

Bạn có thể ngăn chặn điều này bằng cách tuyên bố một cách rõ ràng sở hữu bộ sưu tập của bạn (với một giá trị) cùng với bản đồ của bạn:

class User { 
    String name 
    Set posts = [] 
    static hasMany = [posts: Post] 
} 

Bạn có thể xác định loại bộ sưu tập mà bạn cần. Giá trị mặc định là Set, nhưng nếu bạn cần duy trì đơn đặt hàng, bạn có thể xem xét List hoặc SortedSet.

+2

nên được ' Đặt bài viết = [] ' –

+0

Vâng, mặc định là Đặt, nhưng tôi đã sử dụng Danh sách vì tôi đã giải thích" bài đăng "thành thứ gì đó có thể đặt hàng. SortedSet có lẽ sẽ phù hợp hơn, dù bằng cách nào. –

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