2011-08-31 11 views
6

un escenario de producción real. fondo: 6 tablas: fondo, cuenta, período, peso del período, tenencia, posición.hibernar, cómo cargar objetos complejos en el mundo real

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) 

si tengo un nombre del fondo: fondo falso, que tiene un objetivo holding de IBM (30%), Oracle (20%), GE (50%) para el período (2000-01-01 a 2000-12-31), la posición activa para el 2000-01-01 es 10%, 10%,% 80% y en 2000-01-02 es 20%, 20%, 60% se representará como estos registros en tabla

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% 

la clase java son

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; 
} 

quiero tener una consulta: Base d en la fecha (2000-01-01) y el nombre del fondo (fondo falso). Quiero construir un objeto de Fondo, que contiene la cuenta y el período (2000-01-01 a 2000-12-31), y el período contiene el períodoPeso, y el períodoPeso contiene retenciones, y mantener contiene las posiciones para (2000-01-01) cuando no existe tal posición, por ejemplo, consulto 2000-01-03 y fondo falso, quiero tener la estructura, solo la posición es un conjunto vacío en la explotación.

este hql puede cargar la estructura correctamente si hay datos.

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 

El problema es que cuando no hay datos en la tabla de posiciones para ese día, devuelve nulo. Necesito un sql para darme la estructura cuando no hay datos, puede cargar todo excepto la posición, simplemente deje la posición establecida como vacía.

otra pregunta es, ¿cuál es la mejor forma de cargar una estructura tan compleja? uno hql como estos o cargar parte de la estructura en un hql luego otra parte por otro hql? En sql, siempre los carga uno por uno, primero está el fondo, luego el período, luego el peso, luego la espera, luego la posición, etc. El peso debe ordenarse según el orden de mantenimiento.

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 

es algo realmente cerca, pero esto me da error,

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

"el problema es cuando no hay datos, devuelve nulo" - No hay datos donde? en la asociación de posiciones? –

+0

sí, cuando no hay datos en la tabla de posiciones para la fecha, solo tengo datos para 2000-01-01 y 2000-01-02. cuando consulto 2000-01-03 y "fondo falso", devuelvo la lista vacía de fondos. – Nan

+0

Supongo que mi primera pregunta sería: si quiero cargar un objeto así, ¿debo dividirlo en algunos mini pasos en lugar de un ambicioso proceso de carga de todo a la vez? Simplemente no puedo sentir el beneficio de hibernar si uso demasiados mini pasos. – Nan

Respuesta

0

Usted debe ser capaz de lograr esto cambiando:

inner join fetch h.positions p 

a:

left join fetch h.positions p 

y llamando al

query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 

en su objeto de consulta antes de ejecutar la consulta.

+0

No estoy muy seguro para qué es query.setResultTransformer (CriteriaSpecification.DISTINCT_ROOT_ENTITY). la izquierda une no éxito. aún nulo – Nan

+0

Su consulta utiliza el alias en dos lugares: combinación interna fetch f.period p y unión interna fetch h.positions p, necesita cambiar uno de ellos, luego actualice la cláusula WHERE. –

+0

lo siento, es un error tipográfico, lo he cambiado en la pregunta y pongo el correcto. También puse una solución muy cercana pero que aún no se ha completado. Realmente me pregunto si este vale un hql tan complejo. Estoy totalmente de acuerdo con que uses la búsqueda de combinación de la izquierda, el problema es la condición con. me pide que use filtro y no estoy seguro de cómo usarlo. por cierto, la tabla de posiciones es bastante grande, no se aplica para cargar un montón primero y luego filtrar, tiene que estar configurado en la consulta de la base de datos – Nan

2

Esta es una limitación molesta en HQL, que he encontrado algunas veces con asociaciones basadas en el tiempo.

he encontrado que se trata de una solución a una consulta HQL que contiene fetch y with cláusulas:

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)) 

El truco es mover la cláusula with a la cláusula where y añadir una opción para el objeto a ser nula lo que le permite devolver filas sin una posición.

+3

Desafortunadamente no es equivalente. Pierdes todas las filas que se unen con éxito pero no coinciden con la condición en DÓNDE. Ver ejemplo http://pastebin.com/eY8Vw0xG – okocian

Cuestiones relacionadas