Demander à Hibernate de faire de simples mises à jour, au lieu d’énormes sélections puis mises à jour

StackOverflow https://stackoverflow.com/questions/1009504

Question

Permet de configurer la question en premier.

Ce que j’ai, c’est > 4 tables: client, adresse, commande, articles de commande. Chacun est mappé à l’aide d’Hibernate Annotations et est accessible via une couche Spring DAO / Services.

Ce que j'essaie de faire est de fusionner des clients en double. Il ne reste donc plus que toutes les commandes et adresses associées au client B, il faut mettre à jour leur clé étrangère customer_id pour qu'elle pointe vers le client A. Ensuite, le bit désactivé du client B doit être défini.

Au lieu d’envoyer ces requêtes simples à notre base de données, hibernate devient fou et émet une tonne de requêtes select, puis mises à jour. En particulier, il sélectionne tous les articles attachés à une commande (car ceci est défini EAGER , et ce point n'est pas modifiable.). Pour que les sélections avant la mise à jour cessent de se produire, j’ai essayé d’ajouter l’annotation d’entité hibernate au-dessus du javax.persistence.Entity classique, comme:

@org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = false, dynamicInsert = true)

Cela semblait n'avoir aucun effet, sauf pour les requêtes simples dans lesquelles il ne mettait à jour que des éléments uniques dans une table.

Je récupère les objets en utilisant les critères d'hibernation suivants:

            Criteria c1 = null;
            Criteria c2 = null;
            Criteria c = session.createCriteria(Customer.class);
            c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

            if(resultLimit>0) c.setMaxResults(resultLimit);
            if(timeout>0) c.setTimeout(timeout);
            for(String filter: sqlFilters) {
                if(filter.indexOf("{alias}.customer_")!=-1) c.add(Restrictions.sqlRestriction(filter));
                else if(filter.indexOf("{alias}.address_")!=-1 && addrsAttached) {
                    if(c1==null)
                        c1 = c.createCriteria("addresses").setFetchMode("type", FetchMode.JOIN);
                    c1.add(Restrictions.sqlRestriction(filter));
                } else if(filter.indexOf("{alias}.order_")!=-1 && ordersAttached) {
                    if(c2==null)
                        c2 = c.createCriteria("orders").setFetchMode("orderItems", FetchMode.SELECT);
                    c2.add(Restrictions.sqlRestriction(filter));
                }
            }
            return (List<Customer>) c.list();

Ensuite, je déplace tous les objets d'adresse et de commande du client B vers le client A et exécute un

.
return (Customer) this.getHibernateTemplate().merge(customer);

sur les deux objets client. Ceci finit par créer une tonne d'instructions select qui obtiennent tous les objets associés (par exemple, OrderItems, Products, ProductType, ProductPricingTmpl, etc.)

Je dois faire enlever ces sélections! S'ils n'étaient pas là, la requête aurait l'air normale et serait efficace! Les requêtes de mise à jour en sortie sont parfaites et dynamiques.

Des idées?

Était-ce utile?

La solution

L’indice peut être dans votre choix d’opération merge (). Du javadoc Hibernate:

  

Copier l'état de l'objet donné   sur l'objet persistant avec le   même identifiant. Si il n'y a pas   instance persistante actuellement   associé à la session, il sera   être chargé.

Vous obligez donc Hibernate à charger toutes les données avant de les modifier.

Essayez une autre opération, telle que update ():

  

Mettez à jour l'instance persistante avec   l'identifiant du détaché donné   exemple.

Aucune promesse, cependant, Hibernate pourrait décider de le charger de toute façon. Le fichier dynamicUpdates = true peut en réalité aggraver la situation, car il faut savoir avant de commencer pour pouvoir lancer des mises à jour dynamiques.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top