2011-08-31 22 views
6

một kịch bản sản xuất thực tế. nền: 6 bảng: Quỹ, Tài khoản, thời gian, kỳ hạn, giữ, vị trí.hibernate, Cách tải đối tượng phức tạp trong thế giới thực

Fund: The fund information, for example: fund name, total Asset, start time.. etc. 
Account: each fund has an account (one to one) to fund. 
period: time period (for example: 2000-01-01 to 2000-12-31) 
periodweight: at a certain period, the target holding weight. 
holding: IBM, Oracle, GE are stock holdings. 
position: IBM($3000), oracle($2000), GE($5000) 

nếu tôi có tên quỹ: quỹ giả, có mục tiêu giữ cho IBM (30%), Oracle (20%), GE (50%) trong khoảng thời gian (2000-01-01 đến 2000-12-31), vị trí tác động cho giai đoạn 2000-01-01 là 10%, 10%,% 80% và vào ngày 2000-01-02 là 20%, 20%, 60% sẽ đại diện cho những bản ghi này trong bảng

Account: id account_Number Fund_id 
     * 1   0001  10 
      2   0002  11 

Fund:  id  name     other properties... 
     * 10   fake fund      xxx 
      11   another fake one    xxx 

period: id  start_time  end_time fund_id 
     * 3  2000-01-01  2000-12-31  10 
      4  2001-01-01  2001-12-31  10 

periodWeight: id  target_weight  holding_id period_id 
       *11  30%     21   3 
       *12  20%     22   3 
       *13  50%     23   3 

holding:  id    name   order  other properties... 
      *21    IBM    1    xxx 
      *22    Oracle   2    xxx 
      *23    GE    3    xxx 

position:  id  Account_id holding_id date    actual_position 
       1   1   11   2000-01-01   10% 
       2   1   12   2000-01-01   10% 
       3   1   13   2000-01-01   80% 
       4   1   11   2000-01-02   20% 
       5   1   12   2000-01-02   20% 
       6   1   13   2000-01-02   60% 

Các java class là

Account{ 
    @onetoOne(mappedby="account") 
    Fund f; 

    @oneToMany 
    Set<Position> positions; 
} 

Fund{ 
    @manyToOne 
    Account account; 

    @oneToMany(mappedby="fund") 
    Set<Period> periods; 
} 

Period{ 
    @manyToOne 
    Fund fund; 

    @oneToMany(mappedby="period") 
    Set<PeriodWeight> periodWeights; 
} 

PeriodWeight{ 
    @manyToOne 
    Period period; 

    @ManyToOne 
    Holding holding 
} 

Holding{ 
    @OneToMany(mappedby="holding") 
    Set<PeriodWeight> periodWeights; 

    @OneToMany 
    Set<Position> positions; 
} 

Position{ 
    @manyToOne 
    Account account; 

    @manyToOne 
    Holding holding; 
} 

tôi muốn có một truy vấn: cơ sở d vào ngày (2000-01-01) và tên quỹ (quỹ giả). Tôi muốn xây dựng một đối tượng Quỹ, trong đó có tài khoản và thời gian (2000-01-01 đến 2000-12-31), và khoảng thời gian chứa periodWeight, và periodWeight chứa giữ, và giữ chứa postions cho (2000-01-01). khi không có vị trí như vậy, ví dụ, tôi truy vấn 2000-01-03 và quỹ giả, tôi muốn có cấu trúc, chỉ vị trí là một tập trống trong tổ chức.

hql này có thể tải cấu trúc chính xác nếu có dữ liệu.

select f from Fund f 
inner join fetch f.account a 
inner join fetch f.period p 
inner join fetch p.periodWeight w 
inner join fetch w.holding h 
inner join fetch h.positions po 
where f.name=:name and :date between p.start_date and p.end_date and :date=po.date and po.account= a 

vấn đề là khi không có dữ liệu tại bảng vị trí cho ngày đó, nó sẽ trả về giá trị rỗng. Tôi cần một sql để cho tôi cấu trúc khi không có dữ liệu, nó có thể tải tất cả mọi thứ ngoại trừ vị trí, chỉ cần rời khỏi vị trí thiết lập sản phẩm nào.

một câu hỏi khác là cách tốt hơn để tải cấu trúc phức tạp như thế nào? một hql như thế này hoặc tải một phần của cấu trúc bởi một hql sau đó phần khác bởi một hql? beause trong sql, bạn alway tải chúng từng cái một, đầu tiên là quỹ, sau đó thời gian, sau đó trọng lượng, sau đó giữ, sau đó vị trí vv .. trọng lượng cần phải được sắp xếp dựa trên thứ tự giữ.

select f from Fund f 
inner join fetch f.account a 
inner join fetch f.period p 
inner join fetch p.periodWeight w 
inner join fetch w.holding h 
left join fetch h.positions po with po.account= a and :date=po.date 
where f.name=:name and :date between p.start_date and p.end_date 

là một cái gì đó thực sự chặt chẽ, nhưng điều này cho tôi lỗi,

org.hibernate.hql.ast.QuerySyntaxException: with-clause not allowed on fetched associations; use filters 
+0

"vấn đề là khi không có dữ liệu, nó trả về null" - Không có dữ liệu ở đâu? trong hiệp hội vị trí? –

+0

có, khi không có dữ liệu tại bảng posiion cho ngày, tôi chỉ có dữ liệu cho 2000-01-01 và 2000-01-02. khi tôi truy vấn 2000-01-03 và "quỹ giả", nó trả về danh sách quỹ rỗng. – Nan

+0

Tôi đoán câu hỏi đầu tiên của tôi sẽ là, nếu tôi muốn tải một đối tượng như vậy, tôi có nên chia nhỏ nó thành một số bước nhỏ thay vì tải mọi thứ đầy tham vọng cùng một lúc không? Tôi chỉ không thể cảm thấy lợi ích của ngủ đông nếu tôi sử dụng quá nhiều bước nhỏ. – Nan

Trả lời

0

Bạn sẽ có thể thực hiện điều này bằng cách thay đổi:

inner join fetch h.positions p 

tới:

left join fetch h.positions p 

và gọi

query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 

trên đối tượng truy vấn của bạn trước khi bạn thực hiện truy vấn.

+0

Tôi không chắc chắn query.setResultTransformer (CriteriaSpecification.DISTINCT_ROOT_ENTITY) là gì. sự tham gia bên trái không thành công. vẫn còn null – Nan

+0

Truy vấn của bạn đang sử dụng bí danh p ở hai vị trí: lấy tham số bên trong f.period p và tham số bên trong tìm nạp h.positions p, bạn cần thay đổi một trong số chúng, sau đó cập nhật mệnh đề WHERE. –

+0

xin lỗi, đó là một lỗi đánh máy, tôi đã thay đổi nó trong câu hỏi và đặt đúng. Tôi cũng đặt một giải pháp thực sự gần nhưng chưa có. thực sự tự hỏi điều này có giá trị như một hql phức tạp? Tôi hoàn toàn đồng ý với bạn để sử dụng tìm nạp bên trái, vấn đề là với điều kiện. nó yêu cầu tôi sử dụng bộ lọc và tôi không chắc chắn làm thế nào để sử dụng nó. bằng cách này, bảng vị trí là khá lớn, không áp dụng để tải rất nhiều đầu tiên sau đó lọc, phải được fitlered trên truy vấn cơ sở dữ liệu – Nan

2

Đây là giới hạn gây phiền nhiễu trong HQL, mà tôi đã gặp phải một vài lần với các hiệp hội dựa trên thời gian.

tôi thấy rằng đây là một giải pháp cho một truy vấn HQL chứa fetchwith khoản:

select f from Fund f 
inner join fetch f.account a 
inner join fetch f.period p 
inner join fetch p.periodWeight w 
inner join fetch w.holding h 
left join fetch h.positions po 
where f.name=:name and :date between p.start_date and p.end_date 
and (po is null or (po.account= a and :date=po.date)) 

Bí quyết là để di chuyển các khoản with để mệnh đề where và thêm một lựa chọn cho các đối tượng để được null cho phép nó trả về các hàng với một vị trí.

+3

Thật không may là nó không tương đương. Bạn mất tất cả các hàng đã tham gia thành công nhưng không khớp với điều kiện trong WHERE. Xem ví dụ http://pastebin.com/eY8Vw0xG – okocian

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