2010-09-09 32 views
6

Tôi đang ở vị trí mà công ty chúng tôi có dịch vụ tìm kiếm cơ sở dữ liệu có khả năng cấu hình cao, rất hữu ích để định cấu hình truy vấn theo cách lập trình. Criteria API là mạnh mẽ nhưng khi một trong những nhà phát triển của chúng tôi tái cấu trúc một trong các đối tượng dữ liệu, các hạn chế tiêu chí sẽ không báo hiệu rằng chúng bị hỏng cho đến khi chúng tôi chạy thử nghiệm đơn vị hoặc tệ hơn, trực tiếp và môi trường sản xuất của chúng tôi. Gần đây, chúng tôi đã có một dự án tái cấu trúc về cơ bản gấp đôi thời gian làm việc bất ngờ do vấn đề này, một khoảng trống trong kế hoạch dự án, chúng tôi đã biết nó sẽ mất bao lâu, có lẽ chúng tôi đã có cách tiếp cận khác.Làm cách nào để vượt qua các giới hạn của các tiêu chí và API mẫu của Hibernate?

Tôi muốn sử dụng API mẫu để giải quyết vấn đề này. Trình biên dịch Java có thể lớn tiếng chỉ ra rằng các truy vấn của chúng ta được borked nếu chúng ta đang chỉ định điều kiện 'where' trên các thuộc tính POJO thực. Tuy nhiên, chỉ có rất nhiều chức năng trong API mẫu và nó hạn chế theo nhiều cách. Lấy ví dụ sau

Product product = new Product(); 
product.setName("P%"); 
Example prdExample = Example.create(product); 
prdExample.excludeProperty("price"); 
prdExample.enableLike(); 
prdExample.ignoreCase(); 

Ở đây, bất động sản "tên" đang được truy vấn chống lại (nơi tên như 'P%'), và nếu tôi là để loại bỏ hoặc đổi tên trường "Tên", chúng ta sẽ biết ngay lập tức . Nhưng những gì về tài sản "giá"? Nó bị loại trừ bởi vì đối tượng Product có một số giá trị mặc định cho nó, vì vậy chúng tôi chuyển tên thuộc tính "price" tới một bộ lọc loại trừ. Bây giờ nếu "giá" đã bị xóa, truy vấn này sẽ không hợp lệ về cú pháp và bạn sẽ không biết cho đến khi chạy. QUÈ.

Một vấn đề khác - những gì nếu chúng ta thêm một giây mệnh đề where:

product.setPromo("Discounts up to 10%"); 

Bởi vì cuộc gọi đến enableLike(), ví dụ này sẽ phù hợp trên văn bản quảng cáo "Giảm giá lên đến 10%", mà còn "Giảm giá tới 10.000.000 đô la" hoặc bất kỳ điều gì khác phù hợp. Nói chung, các sửa đổi toàn bộ truy vấn của đối tượng Ví dụ, chẳng hạn như enableLike() hoặc ignoreCase() không phải lúc nào cũng được áp dụng cho mọi thuộc tính đang được kiểm tra.

Đây là vấn đề thứ ba và quan trọng - về các tiêu chí đặc biệt khác? Không có cách nào để có được mọi sản phẩm với mức giá lớn hơn $ 10 bằng cách sử dụng khung mẫu tiêu chuẩn. Không có cách nào để sắp xếp kết quả theo quảng cáo, giảm dần. Nếu đối tượng Product tham gia trên một số Nhà sản xuất, thì không có cách nào để thêm tiêu chí vào đối tượng Nhà sản xuất có liên quan. Không có cách nào để chỉ định FetchMode một cách an toàn trên tiêu chí cho Nhà sản xuất (mặc dù đây là vấn đề với API tiêu chí nói chung - các mối quan hệ được tìm nạp không hợp lệ không âm thầm, thậm chí nhiều hơn một quả bom thời gian)

Cho tất cả những điều trên ví dụ, bạn sẽ cần phải quay lại API tiêu chí và sử dụng các biểu diễn chuỗi các thuộc tính để tạo truy vấn - một lần nữa, loại bỏ lợi ích lớn nhất của các truy vấn mẫu.

Những lựa chọn thay thế nào tồn tại đối với API mẫu có thể nhận được loại lời khuyên biên dịch thời gian mà chúng tôi cần?

+0

Đây là nội dung thú vị nhưng stackoverflow không phải là diễn đàn thảo luận, bạn sẽ không nhận được phản hồi ở đây và câu hỏi của bạn có thể sẽ bị đóng trong biểu mẫu hiện tại. Như đã đề cập trong phần Câu hỏi thường gặp, * "nó cũng hoàn toàn tốt để hỏi và trả lời câu hỏi của riêng bạn, miễn là bạn giả vờ bạn đang ở trên Jeopardy: cụm từ nó dưới dạng một câu hỏi" *. Tôi đề nghị rephrase nó và đăng các chi tiết như câu trả lời. –

+0

@Pascal cảm ơn, tôi sẽ tiếp tục và định dạng lại câu hỏi –

+0

Bạn được chào đón. Và cảm ơn vì đã đăng bài này. –

Trả lời

5

Công ty của tôi cung cấp cho các nhà phát triển những ngày khi chúng tôi có thể thử nghiệm và làm việc trên các dự án thú cưng (a la Google) và tôi đã dành thời gian làm việc để sử dụng các truy vấn mẫu. Tôi đã nghĩ ra điều gì đó có thể hữu ích cho những người khác cũng quan tâm đến Truy vấn mẫu. Dưới đây là ví dụ về khuôn khổ sử dụng ví dụ về Sản phẩm.

Criteria criteriaQuery = session.createCriteria(Product.class); 

Restrictions<Product> restrictions = Restrictions.create(Product.class); 
Product example = restrictions.getQueryObject(); 
example.setName(restrictions.like("N%")); 
example.setPromo("Discounts up to 10%"); 

restrictions.addRestrictions(criteriaQuery); 

Đây là cố gắng khắc phục sự cố trong ví dụ mã từ câu hỏi - vấn đề giá trị mặc định cho trường "giá" không còn tồn tại, vì khung này yêu cầu phải đặt tiêu chí rõ ràng. Vấn đề thứ hai của việc enableLike() đã hết hạn truy vấn - trình ghép chỉ nằm trên trường "name".

Các vấn đề khác được đề cập trong câu hỏi cũng nằm trong khuôn khổ này. Dưới đây là các ví dụ triển khai.

product.setPrice(restrictions.gt(10)); // price > 10 
product.setPromo(restrictions.order(false)); // order by promo desc 
Restrictions<Manufacturer> manufacturerRestrictions 
     = Restrictions.create(Manufacturer.class); 
//configure manuf restrictions in the same manner... 
product.setManufacturer(restrictions.join(manufacturerRestrictions)); 
/* there are also joinSet() and joinList() methods 
    for one-to-many relationships as well */ 

Thậm chí còn có nhiều hạn chế phức tạp hơn.

product.setPrice(restrictions.between(45,55)); 
product.setManufacturer(restrictions.fetch(FetchMode.JOIN)); 
product.setName(restrictions.or("Foo", "Bar")); 

Sau khi thấy khuôn khổ cho một đồng nghiệp, ông nói rằng nhiều dữ liệu ánh xạ đối tượng có setters tin, làm cho loại tiêu chí thiết lập khó khăn cũng như (một vấn đề khác nhau với Ví dụ API!). Vì vậy, tôi cũng đã tính đến điều đó. Thay vì sử dụng setters, getters cũng có thể truy vấn được.

Tôi cũng đã thêm một số kiểm tra thêm đối tượng để đảm bảo an toàn loại tốt hơn - ví dụ: tiêu chí tương đối (gt, ge, le, lt) đều yêu cầu giá trị? mở rộng Comparable cho tham số. Ngoài ra, nếu bạn sử dụng một getter trong phong cách được chỉ định ở trên, và có một chú thích @Transient trình bày trên getter, nó sẽ ném một lỗi thời gian chạy.

Nhưng hãy đợi, còn nhiều hơn nữa!

Nếu bạn thích tiện ích Restricttions được tích hợp sẵn của Hibernate có thể được nhập một cách tĩnh, để bạn có thể làm những việc như criteria.addRestriction (eq ("name", "foo")) mà không làm cho mã của bạn thực sự tiết tùy chọn cho điều đó.

Restrictions<Product> restrictions = new Restrictions<Product>(){ 
     public void query(Product queryObject){ 
     queryObject.setPrice(gt(10)); 
     queryObject.setPromo(order(false)); 
     //gt() and order() inherited from Restrictions 
     }    
} 

Hiện tại, xin cảm ơn bạn rất nhiều vì đã phản hồi! Chúng tôi đã đăng mã trên Sourceforge cho những người quan tâm. http://sourceforge.net/projects/hqbe2/

+0

Tôi thích nó. Có vẻ như bạn đã được truyền cảm hứng từ nhiều khuôn khổ mocking khác nhau? – waxwing

+0

@waxwing yeah Tôi yêu EasyMock :) –

+0

Bạn sẽ kết hợp các hạn chế với hoặc như thế nào? Như trong, "từ người ở độ tuổi> 18 hoặc (tuổi> 16 và parentalApproval)"? – meriton

1

API trông tuyệt vời!

Hạn chế.đơn đặt hàng (boolean) có mùi giống như khớp nối điều khiển. Đó là một chút không rõ ràng những gì các giá trị của đối số boolean đại diện.

Tôi đề nghị thay thế hoặc bổ sung với orderAscending() và orderDescending().

1

Hãy xem Querydsl. Mô-đun JPA/Hibernate của họ yêu cầu tạo mã. Mô-đun bộ sưu tập Java của họ sử dụng proxy nhưng không thể được sử dụng với JPA/Hibernate vào lúc này.

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