hibernate,如何在现实世界中加载复杂对象

Nan*_*Nan 6 hibernate

一个真实的生产场景.背景:6个表:基金,账户,期间,期限,持有,头寸.

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)
Run Code Online (Sandbox Code Playgroud)

如果我有一个基金名称:假基金,其目标持有IBM(30%),甲骨文(20%),通用电气(50%)期间(2000-01-01至2000-12-31), 2000-01-01的实际位置是10%,10%,%80%,2000-01-02是20%,20%,60%将代表这些记录在表中

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%
Run Code Online (Sandbox Code Playgroud)

java类是

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;
}
Run Code Online (Sandbox Code Playgroud)

我想查询:基于日期(2000-01-01)和基金名称(假基金).我想建立一个基金对象,其中包含账户和期间(2000-01-01至2000-12-31),期间包含期货权限,期权包含持有,持有包含持仓(2000-01-01) ).当没有这样的位置时,例如,我查询2000-01-03和假基金,我想拥有结构,只是位置是持有的空集.

如果有数据,这个hql可以正确加载结构.

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
Run Code Online (Sandbox Code Playgroud)

问题是当该位置表中没有数据时,它返回null.我需要一个sql在没有数据时给我结构,它可以加载除位置之外的所有内容,只需将位置设置为空.

另一个问题是加载这种复杂结构的更好方法是什么?一个像这样的hql或由一个hql然后由另一个hql的其他部分加载部分结构?因为在sql中,你总是一个一个地加载它们,首先是基金,然后是期间,然后是权重,然后是持有,然后是位置等.权重需要根据持有顺序进行排序.

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
Run Code Online (Sandbox Code Playgroud)

是真的很接近,但这给了我错误,

org.hibernate.hql.ast.QuerySyntaxException: with-clause not allowed on fetched associations; use filters
Run Code Online (Sandbox Code Playgroud)

jon*_*one 0

您应该能够通过更改来实现此目的:

inner join fetch h.positions p
Run Code Online (Sandbox Code Playgroud)

到:

left join fetch h.positions p
Run Code Online (Sandbox Code Playgroud)

并打电话

query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
Run Code Online (Sandbox Code Playgroud)

在执行查询之前在查询对象上。