Tengo la siguiente consulta y método

private static final String FIND = "SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators LEFT OUTER JOIN FETCH domain.networkCodes WHERE domain.domainId = :domainId";

@Override
public Domain find(Long domainId) {
    Query query = getCurrentSession().createQuery(FIND);
    query.setLong("domainId", domainId);
    return (Domain) query.uniqueResult();
}

Con Domain como

@Entity
@Table
public class Domain {
    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "domain_id")
    private Long domainId;

    @Column(nullable = false, unique = true)
    @NotNull
    private String name;

    @Column(nullable = false)
    @NotNull
    @Enumerated(EnumType.STRING)
    private DomainType type;

    @OneToMany(cascade = {
            CascadeType.PERSIST,
            CascadeType.MERGE
    }, fetch = FetchType.EAGER)
    @JoinTable(joinColumns = {
            @JoinColumn(name = "domain_id")
    }, inverseJoinColumns = {
            @JoinColumn(name = "code")
    })
    @NotEmpty
    @Valid //needed to recur because we specify network codes when creating the domain
    private Set<NetworkCode> networkCodes = new HashSet<>();

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(joinColumns = {
            @JoinColumn(name = "parent", referencedColumnName = "domain_id")
    }, inverseJoinColumns = {
            @JoinColumn(name = "child", referencedColumnName = "domain_id")
    })
    private Set<Domain> operators = new HashSet<>();
    //more
}

Yo esperaría que este sola consulta para obtener los Set<NetworkCode> y Set<Domain> relaciones, pero no es así. Decir que el Domain me consulta tiene dos operadores, Hibernate iba a realizar 1 + 2 * 2 = 5 consultas

Hibernate: select distinct domain0_.domain_id as domain1_1_0_, domain2_.domain_id as domain1_1_1_, networkcod4_.code as code2_2_, domain0_.name as name1_0_, domain0_.type as type1_0_, domain2_.name as name1_1_, domain2_.type as type1_1_, operators1_.parent as parent1_0__, operators1_.child as child4_0__, networkcod3_.domain_id as domain1_1_1__, networkcod3_.code as code5_1__ from domain domain0_ left outer join domain_operators operators1_ on domain0_.domain_id=operators1_.parent left outer join domain domain2_ on operators1_.child=domain2_.domain_id inner join domain_network_codes networkcod3_ on domain0_.domain_id=networkcod3_.domain_id inner join network_code networkcod4_ on networkcod3_.code=networkcod4_.code where domain0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?
Hibernate: select operators0_.parent as parent1_1_, operators0_.child as child4_1_, domain1_.domain_id as domain1_1_0_, domain1_.name as name1_0_, domain1_.type as type1_0_ from domain_operators operators0_ inner join domain domain1_ on operators0_.child=domain1_.domain_id where operators0_.parent=?
Hibernate: select networkcod0_.domain_id as domain1_1_1_, networkcod0_.code as code5_1_, networkcod1_.code as code2_0_ from domain_network_codes networkcod0_ inner join network_code networkcod1_ on networkcod0_.code=networkcod1_.code where networkcod0_.domain_id=?

Supongo que esto es porque me estoy uniendo a los operadores Domain, sino que tiene que unirse a ellos mismos.

Hay una consulta HQL puedo ejecutar que iba a hacer tanto?

OriginalEl autor Sotirios Delimanolis | 2013-08-27

7 Comentarios

  1. 11

    Si usted sabe que usted tiene sólo dos niveles en el árbol, ¿has pensado en unirse a un nivel más profundo. Algo como la siguiente?

    SELECT DISTINCT domain FROM Domain domain 
      LEFT OUTER JOIN FETCH domain.operators operators1 
      LEFT OUTER JOIN FETCH domain.networkCodes 
      LEFT OUTER JOIN FETCH operators1.operators operators2 
      LEFT OUTER JOIN FETCH operators1.networkCodes
    WHERE domain.domainId = :domainId

    OriginalEl autor Andrei I

  2. 13

    La Hibernación de las Relaciones de las Obras con diferentes Fetch Estrategias..!!

    Hibernate proporciona 4 estrategias para la recuperación de datos:

    SELECCIONE

    @OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
    @Column(name="id") 
    @Fetch(FetchMode.SELECT)

    En este Método, existen Múltiples SQLs despedido. Este primero es despedido
    para recuperar todos los registros de la tabla principal. El resto son
    despedido por la recuperación de registros para cada Registro Primario. Esto es, básicamente,
    el N+1 problema. La primera consulta recupera de N registros de la base de datos, en
    este caso N registros primarios. Para cada uno de los Padres de una nueva consulta recupera
    Niño. Por lo tanto, para N de los Padres, N consultas de recuperar la información de
    Tabla secundaria.

    UNIRSE

    @OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
    @Column(name="id")
    @Fetch(FetchMode.JOIN) 

    Esto es similar a la estrategia de recuperación, excepto que el hecho de que todos los
    recuperación de base de datos se efectúe inmediatamente en JOIN fetch a diferencia de SELECCIONAR
    dónde ocurre en base a la necesidad. Esto puede convertirse en un importante
    el rendimiento de consideración.

    SUBSELECCIÓN

     @OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
     @Column(name="id")
     @Fetch(FetchMode.SUBSELECT)

    Dos Sql son despedidos. Uno para recuperar todos los Padres de familia y la segunda utiliza un
    SUBSELECCIÓN consulta en la cláusula where para recuperar todos los niños que ha
    la coincidencia de los padres id.

    LOTE

    @OneToMany(mappedBy="tableName", cascade=CascadeType.ALL)
    @Column(name="id")
    @@BatchSize(size=2)

    El tamaño de lote de mapas para el número de Padres cuyo hijo se recuperan.
    Entonces podemos especificar el número de registros que se obtienen en un tiempo.Pero
    Varias consultas será ejecutado.!!

    uno-a-muchos & muchos-a-muchos le permite unirse, selección y Subselección

    muchos-a-uno & uno-a-uno permite Unirse y Seleccione


    Hibernate también distingue entre (cuando es el de las asociaciones se recuperan)

    1.Recuperación inmediata

    de una asociación, de colección o atributo se recupera inmediatamente, cuando
    el Padre está cargado. (lazy=»false»)

    2.Colección perezosa buscar

    una colección se recupera cuando la aplicación invoca una operación sobre
    esa colección. (Este es el valor predeterminado para las colecciones.(lazy=»true»)

    3.»Extra-perezoso» de la colección de captura –

    elementos individuales de la colección se accede a través de la base de datos
    como sea necesario. Hibernate no intenta recuperar toda la colección en
    la memoria a menos que sea absolutamente necesario (muy apropiado para grandes colecciones)
    (lazy=»extra»)

    4.Proxy buscar

    un valor único de asociación se recupera cuando un método distinto a la
    identificador de captador es invocado sobre el objeto asociado.
    (lazy=»proxy»)

    5.»No-proxy» captura –

    un valor único de asociación se recupera cuando la variable de instancia es
    accede. En comparación con proxy ir a buscar, este enfoque es menos perezoso.(lazy=»no-proxy»)

    6.Perezoso atributo de captura –

    un atributo o un único valor de la asociación se recupera cuando la instancia
    se accede. (lazy=»true»)

    uno-a-muchos & muchos-a-muchos permite Inmediato, Layzy, Extra Perezoso

    muchos-a-uno & uno-a-uno permite la Inmediata Proxy, Proxy No

    Esta es una buena referencia, pero no puedo utilizar @Fetch con HQL.
    usted puede agregar estrategia de recuperación como Extra-perezoso en la JPA de la clase, de modo que el interior de las consultas no se ejecutará a menos que el acceso al interior de las tablas de relación. Por esto sólo será la obtención de los valores de la tabla principal, el resto será ignorado y que también con una SOLA consulta.

    OriginalEl autor Dileep

  3. 3

    Que marcó sus asociaciones con GANAS. Así, lo que usted hace en su consulta, Hibernate cargar todos los dominios asociados y de los códigos de red de la carga de los dominios. Y será la carga de los dominios y de los códigos de red de los dominios adicionales, etc. etc. hasta que todos los de la colección de cargas de retorno vacío colecciones o entidades que ya han sido cargados.

    Para evitar que, hacer que sus colecciones perezoso (por defecto). A continuación, la carga de un dominio con sus operadores y sus códigos de red se carga sólo eso.

    Las colecciones deben ser EAGER para que se inicializa en mi Transaction límites. Yo los uso en mi capa de la vista. Me pregunto si es posible cargar todos los operadores/networkcodes de una sola vez, en lugar de una consulta para cada Domain.
    No sin el uso de propiedad SQL (ver docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm por ejemplo), o sin necesidad de ajustar el modelo para introducir, por ejemplo, la raíz del árbol en cada nodo hijo, y la carga de todos los dominios que tienen el mismo nodo raíz. No puedes simplemente hacer todo lo pereza y utilizar OpenSessionInView? Hacer muchos asociación con ganas es casi siempre una mala idea, especialmente si recursiva: esto lo hace con ganas de todos de caso de uso, incluyendo aquellos que solo necesitan de carga de una entidad específica.
    El problema no es la carga diferida. Todos los datos que va a ser recuperada independientemente. No quiero enviar toneladas de solicitudes SQL. Voy a tomar una mirada cuidadosa en el documento vinculado. Darle un par de días. Gracias.
    Entiendo su preocupación. Pero lo que la asociación con ganas causará la misma toneladas de ejecución de la solicitud, salvo que sea para cada caso de uso, y no sólo para los casos de uso que necesitan las asociaciones para ser cargado actualmente. Que hace que sea mucho peor.
    Usted no me coge: no sólo los casos de uso que utilizar esa consulta. Todos los casos de uso que, de una u otra manera, la carga de un dominio a partir de la base de datos. Todos los operadores de la carga de dominio, y los operadores de los operadores, etc. siempre será cargado cuando la carga de un dominio a través de alguna consulta, session.get() o la navegación a través de la gráfica de entidades.

    OriginalEl autor JB Nizet

  4. 2

    Tu con GANAS de asignación sólo será considerado automáticamente por Hibernate si utiliza la API de Criterios para la consulta.

    Si utiliza HQL, usted tendrá que agregar manualmente el traer a tu palabra clave se Une a la fuerza de Hibernación para incluir las relaciones en la primera consulta y evitar posteriores consultas.

    Este es Hibernate-específicos y pueden funcionar de forma diferente en otros Orm.

    Ver esta pregunta/respuesta para un ángulo ligeramente diferente.

    OriginalEl autor sola

  5. 1

    No documentado que bueno, pero ¿se trata de ajustar el FetchMode?
    Puede hacerlo utilizando el API de Criterios: domainCriteria.setFetchMode("operators", JOIN) o uso @Fetch(JOIN) en la definición de relación.

    La anotación (y sólo la anotación como parece) también permite establecer un modo de captura SUBSELECT, que debería al menos evitemos de Hibernación para ejecutar 3 consultas max. No saber de su conjunto de datos, supongo que este debe ser el camino a seguir para que usted, como un grande y gordo, únase a más de los cuadros no parece muy saludable. Mejor descubrirlo por ti mismo, supongo…

    Mis consultas HQL ya FETCH JOIN. Voy a tratar de los SUBSELECT.
    No estoy seguro de si el HQL la notación que usa es en realidad el mismo que el «modo de captura» como se entiende por hibernate. Afaik, el HQL JOIN FETCH es sólo medios para decir «ah, y por cierto, inicializar el que las relaciones totalmente, y no sólo obtener los IDs» – Hibernate no interpretar esto como a qué tipo de estrategia se debe aplicar para la obtención, como la que precede a la JOIN es simplemente la sintaxis necesaria para aplicar la FETCH. Pero, como esto se menciona explícitamente, puede que haya sido la mezcla de mi experiencia con HQL & anotación de uso.
    Ah, y como usted trae su HQL: como se ha anotado el realtions con EAGER de todos modos, hace tu consulta producir cualquier resultado diferente de la de un simple «SELECT DISTINCT de dominio DE Dominio de dominio en el dominio.domainId = :domainId»? Y por qué la DISTINCT? como domainId es el PK, ¿cómo puede haber nunca más de un resultado?
    Lo siento por tomar tanto tiempo para responder. resulta que no Se puede utilizar @Fetch con HQL. Como para el DISTINCT, yo estaba teniendo algunos problemas con JOIN que lo requerían. Podría ser redundante en algunas de estas consultas. Voy a limpiar eso, pero no le hace ningún daño ahora afaik.

    OriginalEl autor skirsch

  6. 0

    Mi primera observación es que usted no necesita escribir una consulta HQL que contienen combinaciones de si su asignación decir que debe ser cargado con impaciencia.

    Sin embargo, puede decirle a la Hibernación para utilizar la estrategia de recuperación como sub seleccione si usted no desea utilizar combinaciones.

    Hibernate genera la consulta SQL para cargar los objetos durante el inicio basado en la especifica las asignaciones y se almacena en caché. Sin embargo, en su caso, tiene de uno a muchos anidada relación con uno mismo y con profundidad arbitraria, por lo que parece no va a ser posible para que hibernate decidir antes de la mano
    el sql correctamente con ganas de captura. Por lo que tendría que enviar varias combinaciones de consultas dependiendo de la profundidad de los padres de Dominio se consulta en tiempo de ejecución.

    Me parece que estás pensando que HQL y la resultante de SQL/(‘s) en su caso puede tener de uno a uno correpondence que no es
    verdadero. Con HQL consulta de los objetos y el orm decide cómo cargar el objeto y sus relaciones (con ganas/perezoso), basado en la
    las asignaciones o se pueden especificar en tiempo de ejecución ( por e.g, un perezoso de la asociación en la asignación puede ser reemplazado por una Consulta a la api, pero no viceversa).
    Usted puede decirle al orm qué carga ( mi marca con ganas o perezoso ) y cómo cargar con impaciencia ( ya sea a través de ingreso /sub seleccionar).

    ACTUALIZACIÓN

    Cuando yo ejecute la consulta siguiente en el modelo de dominio

    SELECT DISTINCT domain FROM Domain domain LEFT OUTER JOIN FETCH domain.operators LEFT OUTER JOIN FETCH domain.networkCodes WHERE domain.domainId = :domainId";

    Puedo ver que el networkCode y operador de colecciones de instancia PersistentSet ( esto es Hibernate contenedor) y ambos han inicializado conjunto de propiedades para ser verdad. También en el subyacente contexto de la sesión puedo ver los dominios con el dominio y los operadores que se muestran.
    Entonces, ¿qué te hace pensar que no son ansiosamente cargado ?

    Esta es la forma en que mi dominio se parece a

    @Entity
    @Table
    public class Domain {
    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "domain_id")
    private Long domainId;
    @Column(nullable = false, unique = true)   
    private String name;
    @Column(nullable = false)    
    @Enumerated(EnumType.STRING)
    private DomainType type;
    @OneToMany(mappedBy = "domain",cascade = {
    CascadeType.PERSIST,
    CascadeType.MERGE
    }, fetch = FetchType.EAGER)   
    private Set<NetworkCode> networkCodes = new HashSet<NetworkCode>();
    @ManyToMany(mappedBy="parent",fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    private Set<Domain> operators = new HashSet<Domain>();
    //more
    @ManyToOne  
    private Domain parent;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public DomainType getType() {
    return type;
    }
    public void setType(DomainType type) {
    this.type = type;
    }
    public Set<Domain> getOperators() {
    return operators;
    }
    public Long getDomainId() {
    return domainId;
    }
    public void setDomainId(Long domainId) {
    this.domainId = domainId;
    }
    public void setOperators(Set<Domain> operators) {
    this.operators = operators;
    }
    public void addDomain(Domain domain){
    getOperators().add(domain);
    domain.setParent(this);
    }
    public Domain getParent() {
    return parent;
    }
    public void setParent(Domain parent) {
    this.parent = parent;
    }
    public void addNetworkCode(NetworkCode netWorkCode){
    getNetworkCodes().add(netWorkCode);
    netWorkCode.setDomain(this);
    }

    Hibernate HQL join fetch no de forma recursiva a que la obtención de

    El JOIN en el HQL no es sólo para EAGER de carga, es para la LEFT OUTER. No cada dominio tiene operators o networkCodes. El LEFT OUTER JOIN es necesario para la correcta asignación.
    Ver mis actualizaciones anteriores.
    El problema no es que no está cargado con impaciencia. Es que hay OMI demasiadas consultas SQL generado. Yo creo que Hibernación podría hacer con menos.
    Entiendo que ahora. Creo que en ese caso, Andrei la respuesta es su mejor opción !

    OriginalEl autor Shailendra

  7. 0

    Puesto que ya ha especificado FetchType.EAGER tanto networkCodes y operators, cada vez que se consulta domain, hibernate carga tanto networkCodes y operators. Esa es la idea de EAGER ir a buscar el modo de

    Por lo que podría cambiar su consulta simple a lo siguiente:

    private static final String FIND
    = "SELECT DISTINCT domain"
    + " FROM Domain domain"
    + " WHERE domain.domainId = :domainId";

    Los detalles de API aquí

    Saludos !!

    Con GANAS de captura no significa que hibernate se ejecutará una sola consulta sql: significa que todos los objetos que debe ir a buscar ansiosamente será recuperar al mismo tiempo que el objeto raíz (es decir, NO necesariamente en la misma consulta)
    Sí tienes razón, no necesariamente la misma consulta pero pueden ser cargados al mismo tiempo.
    Tenga en cuenta que mi consulta no es un simple JOIN, es un LEFT OUTER JOIN. No puedo deshacerme de que como la devolución de las entidades no será correcta.

    OriginalEl autor Sachin Thapa

Dejar respuesta

Please enter your comment!
Please enter your name here