Vraag Complexe zoekopdracht vraagt ​​JPA


In mijn Wicket + JPA / Hibernate + Spring-project is een groot deel van de functionaliteit gebaseerd op de pagina Inbox, waarbij gebruikers veel filteropties gebruiken (niet allemaal moeten ze worden gebruikt), waardoor gebruikers de verzameling objecten kunnen beperken waarmee ze willen werken . Ik vroeg me af wat de beste strategie is om deze filtering te implementeren? In de oude versie van deze toepassing is de zoekopdracht samengesteld uit aaneenschakelingsstrings met SQL-voorwaarden. Onlangs las ik over de nieuwe API van Criteria die de API biedt - zou u dit aanbevelen tijdens het werken met de zoekreeks? En hoe wordt dit gecombineerd met de DAO-laag: bouwt de zoekopdracht met Criteria API in de bedrijfslaag geen breuk op bij het scheiden van lagen?


10
2017-10-22 13:15


oorsprong


antwoorden:


Voor het filteren van query's zoals u beschrijft, raad ik aan om de API voor Hibernate- of JPA-criteria te gebruiken vanwege de ondersteuning voor voorwaardelijke query's. Ik heb meestal gewoon de bouwcode van de criteria in mijn DAO's gezet en geef daar alle vereiste (mogelijk nul) argumenten door.

Hier is een voorbeeld van de DAO-methode van een voorbeeld van een autohuurtoepassing met behulp van de Hibernate-criteria-API:

public List<VehicleRentalContract> list(Long contractID,
            String customerNameOrID, Date date,
            String vehicleDescriptionOrRegistration) {
        Criteria criteria = getSession().createCriteria(
                VehicleRentalContract.class);
        // contractID filter
        if (contractID != null && contractID != 0) {
            criteria.add(Restrictions.eq("id", contractID));
        }
        // customerNameOrID filter
        if (customerNameOrID != null && customerNameOrID.length() > 0) {
            try {
                Long customerID = Long.parseLong(customerNameOrID);
                criteria.add(Restrictions.eq("customer.id", customerID));
            } catch (NumberFormatException e) {
                // assume we have a customer name
                String customerNameQuery = "%" + customerNameOrID.trim() + "%";
                criteria.createAlias("customer", "customer").add(
                        Restrictions.or(Restrictions.like("customer.firstName",
                                customerNameQuery), Restrictions.like(
                                "customer.lastName", customerNameQuery)));
            }
        }
        // date filter
        if (date != null) {
            criteria.add(Restrictions.and(
                    Restrictions.le("rentalPeriod.startDate", date),
                    Restrictions.ge("rentalPeriod.endDate", date)));
        }

        // vehicleDescriptionOrRegistration filter
        if (vehicleDescriptionOrRegistration != null
                && vehicleDescriptionOrRegistration.length() > 0) {
            String registrationQuery = "%"
                    + Vehicle
                            .normalizeRegistration(vehicleDescriptionOrRegistration)
                    + "%";
            String descriptionQuery = "%"
                    + vehicleDescriptionOrRegistration.trim() + "%";

            criteria.createAlias("vehicle", "vehicle").add(
                    Restrictions.or(Restrictions.like("vehicle.registration",
                            registrationQuery), Restrictions.like(
                            "vehicle.description", descriptionQuery)));
        }

        List<VehicleRentalContract> contracts = criteria.list();
        return contracts;
}

De createAlias-aanroep kan worden gebruikt waar u een join in SQL nodig hebt.


4
2017-10-25 14:10



zelfs als ik liever Criteria gebruik dan HQL en SQL, zal er voor mij modulariteit en ook performance zijn, want wanneer het project in productie komt, is het grootste probleem waar we mee te maken hebben, noch HQL, noch SQL kan Criteria over prestaties halen.

Toevoegen aan bovenstaande De DAO-laag wordt gemaakt om toegang te krijgen tot de gegevens, en deze laag moet zo helder zijn als glas zonder complexe codering of bedrijfslogica, maar in het geval van criteria moet een logica worden geschreven (criteria maken) om te komen tot een een betere en verbeterde manier om toegang te krijgen tot het object. Dus naar mijn mening is er geen inbreuk op het plaatsen van zoveel logica in de DAO-laag.


1
2017-10-27 13:29



Twee benaderingen:

1 .. Afhankelijk van het type filter dat u nodig heeft, kunt u dit misschien bereiken door te zoeken op b.v. indexeer alle objecten met Lucene en gebruik vervolgens zoekopdrachten om de filtering uit te voeren. bijvoorbeeld een vraag opbouwen zoals:

titel: "The Right Way" & mod_date: [20020101 TO 20030101]

Zien: http://lucene.apache.org/java/2_4_0/queryparsersyntax.html


2 .. Of met behulp van criteria ...

Ik zou de nieuwe api type-safe criteria uit de slaapstand gebruiken:

http://relation.to/12805.lace

In plaats van een methode die een zeer groot criterium opbouwt, zou ik proberen om alle logica los te laten met behulp van vrijstaande criteria -

http://docs.jboss.org/hibernate/core/3.5/reference/en/html/querycriteria.html#querycriteria-detachedqueries

Met een combinatie van deze twee zou je gemakkelijk criteria kunnen opbouwen.

Een andere plaats om naar inspiratie te zoeken, is de graals dynamische vinders. Dit is in wezen wat u op een statische manier probeert te bereiken.

http://www.grails.org/doc/1.0.x/guide/single.html#5.4.1 Dynamische zoekers

Als u echt volledige scheiding van lagen wilt, kunt u een eenvoudige grammatica implementeren. Vervolgens ontleed dit om de relevante criteria te creëren. Dit zou het mogelijk maken om de onderliggende criteria-implementaties te veranderen. Of dit passend is, hangt af van hoe cruciaal deze abstractie voor jou is.


1
2017-10-30 21:38