[ALG] Waar laat ik mijn queries?

Pagina: 1
Acties:
  • 243 views sinds 30-01-2008
  • Reageer

  • RSchellhorn
  • Registratie: Augustus 2001
  • Laatst online: 02-05 20:03
Situatie:
Ik ben bezig met een relatief simpel programma, dat gebruikt maakt van een database om zijn gegevens in op te slaan, om te praten met de database gebruik ik (uiteraard) sql. Verder nog: het programma wordt in Java 5.0 geschreven (webinterface in jsp) en er zullen weinig concurrent users zijn (25 zal veel zijn, is voor inter gebruik).

Probleem
Waar laat ik mijn queries? Specifieker: om het programma goed onderhoudbaar te houden. Normaal gebruik ik twee manieren, namelijk gewoon inline in de code een querystring typen of een stored procedure gebruiken. Beide methoden gaan gepaard met voor- en nadelen.

Inline werkt makkelijk, todat er iets moet veranderen.... Een object dat een een extra attribuut krijgt, kan tot gevolg hebben dat je in veel klasses op zoek moet gaan naar queries, die veranderd moeten worden. Dit werkt dus zeker niet ideaal.

Voor stored procedures verwijs ik als leesvoer maar naar: http://gathering.tweakers.net/forum/list_messages/949801/0. Omdat ik zelf de database moet migreren van ms access naar mysql snap ik gelijk waarom stored procedures evil zijn, ik zou ze allemaal moet herschrijven! (Access gebruikt gewoon een query, mysql vereist wat meer werk)

Wat heb ik zelf bedacht?
Toevallig ben ik pas met het ImageRegistry voor SWT bezig geweest en volgens mij kan zo'n constructie ook hier handig zijn. Een Registry zorgt er voor dat er maar een instantie van een resource gemaakt wordt. De queries worden gewoon opgeslagen in een bestand, die je met een willekeurige editor kan bewerken, ze worden geidentificeerd met een unieke (bestands)naam. Zodra je programma een query moet uitvoeren wordt het bestand ingelezen en omgezet naar een PreparedStatement, een volgende keer kan dit object zo uit het QueryRegistry worden terug gegeven.

Dit heeft wel tot gevolg dat een query niet meerdere keren op het zelfde tijdstip uitgevoerd mag worden, maar dat kan ik garranderen in mijn app.

Hoe werken jullie en waarom?
... en kan mijn manier werken of kunnen jullie zo al dingen verzinnen waarom dit nooit zal gaan?

"Ik heb zo veel soep gegeten, dat kan een mens niet aan. Ik heb zo veel soep gegeten, kan bijna niet meer staan. Ik zat daar maar te slurpen achter die grote kop en als ik bijna klaar was, dan schepten ze weer op!" (Hans Teeuwen)


  • zneek
  • Registratie: Augustus 2001
  • Laatst online: 08-02-2025
Tip: www.hibernate.org

Hibernate is een O/R mapper. Kort gezegd ben je dan voor een groot deel van queries af, en kun je de meeste zaken in je objecten oplossen.

  • RSchellhorn
  • Registratie: Augustus 2001
  • Laatst online: 02-05 20:03
Bedankt voor de tip, ik ken hibernate. Alleen was ik niet naar zo'n oplossing opzoek, voor deze app wil ik zelf een DAL maken. Voor andere programma's dus bedankt, maar nu wil ik gewoon graag weten waar ik queries voor een eigen DAL laat.
(had ik er wellicht ook gelijk bij moeten zetten, sorry)

"Ik heb zo veel soep gegeten, dat kan een mens niet aan. Ik heb zo veel soep gegeten, kan bijna niet meer staan. Ik zat daar maar te slurpen achter die grote kop en als ik bijna klaar was, dan schepten ze weer op!" (Hans Teeuwen)


  • zneek
  • Registratie: Augustus 2001
  • Laatst online: 08-02-2025
Slayer08 schreef op zaterdag 21 mei 2005 @ 10:42:
Bedankt voor de tip, ik ken hibernate. Alleen was ik niet naar zo'n oplossing opzoek, voor deze app wil ik zelf een DAL maken. Voor andere programma's dus bedankt, maar nu wil ik gewoon graag weten waar ik queries voor een eigen DAL laat.
(had ik er wellicht ook gelijk bij moeten zetten, sorry)
Als je dan per se queries wilt gebruiken zou ik ze op een centrale plek knallen, in een soort van DAO. Een oplossing die ik nog wel eens gebruik, ook in combinatie met hibernate. Voordeel is dat je queries die gaan over bijv Klant in de KlantSqlDao staan. wijzigt de Klant tabel en class, weet je dus precies waar je moet zijn.

Wat daarnaast misschien nog een tip is is om met Unit tests te gaan werken, zodat je na een wijziging al je Daos ( en dus al je queries ) kunt testen op correctheid. Dan glipt er geen query fout door naar je productieomgeving.

  • RSchellhorn
  • Registratie: Augustus 2001
  • Laatst online: 02-05 20:03
Ik heb nu dit soort code:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class UserDAO {
// ...
    public User retrieve(String login, String password) throws DALException {
        assert invariant() : "PRE: The invariant must hold";
        assert login != null : "PRE: The login must be an instance";
        assert password != null : "PRE: The password must be an instance";

        String query = "SELECT Users.Login AS User_Login, [nog meer] FROM Users WHERE Users.Login=? AND Users.Password=?";

        try {
            Preparedstatement = getConnection().prepareStatement(query);

            // Set the parameters
            statement.setString(1, login);
            statement.setString(2, password);

            // return the first (only) user, else return null
            ResultSet result = statement.executeQuery();

            User user = result.next() ? convertOne(result) : null;

            statement.close();

            return user;
        } catch (SQLException e) {
            throw new DALException(e);
        }
    }
//..
}


Ik ben juist op zoek naar een alternatief voor die inline query.

Unit tests zijn klaar :), alleen de database (access) ondersteund geen transacties, dus ik kan ze nog niet runnen zonder mijn db te corrupten. (setSavepoint() gooit een exceptie dat deze feature niet beschikbaar is met access)

[ Voor 13% gewijzigd door RSchellhorn op 21-05-2005 10:59 ]

"Ik heb zo veel soep gegeten, dat kan een mens niet aan. Ik heb zo veel soep gegeten, kan bijna niet meer staan. Ik zat daar maar te slurpen achter die grote kop en als ik bijna klaar was, dan schepten ze weer op!" (Hans Teeuwen)


  • zneek
  • Registratie: Augustus 2001
  • Laatst online: 08-02-2025
Slayer08 schreef op zaterdag 21 mei 2005 @ 10:58:
Ik heb nu dit soort code:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class UserDAO {
// ...
    public User retrieve(String login, String password) throws DALException {
        assert invariant() : "PRE: The invariant must hold";
        assert login != null : "PRE: The login must be an instance";
        assert password != null : "PRE: The password must be an instance";

        String query = "SELECT Users.Login AS User_Login, [nog meer] FROM Users WHERE Users.Login=? AND Users.Password=?";

        try {
            Preparedstatement = getConnection().prepareStatement(query);

            // Set the parameters
            statement.setString(1, login);
            statement.setString(2, password);

            // return the first (only) user, else return null
            ResultSet result = statement.executeQuery();

            User user = result.next() ? convertOne(result) : null;

            statement.close();

            return user;
        } catch (SQLException e) {
            throw new DALException(e);
        }
    }
//..
}


Ik ben juist op zoek naar een alternatief voor die inline query.

Unit tests zijn klaar :), alleen de database (access) ondersteund geen transacties, dus ik kan ze nog niet runnen zonder mijn db te corrupten. (setSavepoint() gooit een exceptie dat deze feature niet beschikbaar is met access)
Ik snap je wens wel, maar ik zie daar niet echt een oplossing voor. Je zit namelijk hoe dan ook vast aan harde afhankelijkheden. De query zou je prima in een externe registry kunnen gooien, maar de rest van je code is nog steeds hard afhankelijk van die query. Als je de db zoveel wijzigt dat die convertOne niet meer werkt, wat dan?

Ik zie het voordeel niet van puur de query tekst uit bovenstaande voorbeeld halen.

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 22-03 18:12
Je kunt kiezen voor een query object welke dan door een aparte class vertaald wordt naar SQL. Je kunt ook kiezen voor een verzamel class voor alle queries. Daaraan vraag je dan per specifieke actie de juiste query. Ook erg handig als je je app wil aansluiten op een andere DB waarvan het SQL dialect erg veel verschilt van de huidige.

Noushka's Magnificent Dream | Unity


  • ReallyStupidGuy
  • Registratie: Januari 2002
  • Laatst online: 01-05 10:31
Toch zijn stored procedures hiervoor wel een oplossing, bovendien kun je als je het grondig aanpakt de beveiliging van je database optimaliseren (rechten op stored procedures ipv tabellen).

Storede procedures zijn imo niet evel, ms-access is evil!

Ik weet niet hoe ms-access werkt met stored procedures maar als het idee gelijk is dan zou het herschrijven niet zo moeilijk moeten zijn, voornamelijk syntax en dan nog wat dingen die mysql misschien niet kan wat access wel kan.

Duizend wijzen kunnen meer vragen stellen dan één idioot kan beantwoorden.


  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 04-05 13:54
een simpele property file zou moeten lukken !

"Live as if you were to die tomorrow. Learn as if you were to live forever"


  • RSchellhorn
  • Registratie: Augustus 2001
  • Laatst online: 02-05 20:03
zneek schreef op zaterdag 21 mei 2005 @ 11:02:
[...]
Als je de db zoveel wijzigt dat die convertOne niet meer werkt, wat dan?
Humm misschien heb je hier wel een punt, deze functie verzorgt uiteraard de binding tussen attribuut van user en kolomnaam. Dus

Java:
1
2
String name = resultSet.getString("User_Login");
User user = new User(name);


Veranderingen in het model resulteren dus altijd in het aanpassen van en de queries en deze convertOne-methode. Ik zal dus met het handmatig aanpassen van deze binding moeten leven, of een geheel generieke oplossing moeten kiezen (wat niet aan de orde is).

Kan iemand iets zinnigs zeggen of ik het PreparedStatement moet opslaan in een register of gewoon zo moet laten staan?

"Ik heb zo veel soep gegeten, dat kan een mens niet aan. Ik heb zo veel soep gegeten, kan bijna niet meer staan. Ik zat daar maar te slurpen achter die grote kop en als ik bijna klaar was, dan schepten ze weer op!" (Hans Teeuwen)


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Slayer08 schreef op zaterdag 21 mei 2005 @ 11:19:
Veranderingen in het model resulteren dus altijd in het aanpassen van en de queries en deze convertOne-methode. Ik zal dus met het handmatig aanpassen van deze binding moeten leven, of een geheel generieke oplossing moeten kiezen (wat niet aan de orde is).
Waarom niet?
Ik heb ongeveer hetzelfde gedaan, maar ik heb ook nog een functie als User.getFields die "Users.Login AS User_Login, [nog meer]" returned.
Deze functie is zeg maar gekoppeld aan convertOne. Als je dan een veld aan de Users tabel toevoegd, hoef je alleen User.getFields en convertOne aan te passen en niet elke query die daar gebruik van maakt.

  • RSchellhorn
  • Registratie: Augustus 2001
  • Laatst online: 02-05 20:03
OlafvdSpek schreef op zaterdag 21 mei 2005 @ 11:50:
[...]

Waarom niet?
Ik heb ongeveer hetzelfde gedaan, maar ik heb ook nog een functie als User.getFields die "Users.Login AS User_Login, [nog meer]" returned.
Deze functie is zeg maar gekoppeld aan convertOne. Als je dan een veld aan de Users tabel toevoegd, hoef je alleen User.getFields en convertOne aan te passen en niet elke query die daar gebruik van maakt.
Hummm kan handig zijn, bijvoorbeeld een Map<String, String> die dus het tuple ("Users.Login","User_Login") opslaat. Klinkt netjes, ga ik zeker naar kijken!

De conversie van zo'n map naar de SELECT is natuurlijk een eitje dan.

*Dat soms de mooie oplossingen zo simpel zijn... _/-\o_

[ Voor 9% gewijzigd door RSchellhorn op 21-05-2005 12:04 ]

"Ik heb zo veel soep gegeten, dat kan een mens niet aan. Ik heb zo veel soep gegeten, kan bijna niet meer staan. Ik zat daar maar te slurpen achter die grote kop en als ik bijna klaar was, dan schepten ze weer op!" (Hans Teeuwen)


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Slayer08 schreef op zaterdag 21 mei 2005 @ 12:02:
Hummm kan handig zijn, bijvoorbeeld een Map<String, String> die dus het tuple ("Users.Login","User_Login") opslaat. Klinkt netjes, ga ik zeker naar kijken!
Ik zou Login in plaats van Users.Login opslaan voor het geval je een keer een alias voor een tabel moet gebruiken. Dan kun je Users. meegeven aan de getFields functie.

  • Varienaja
  • Registratie: Februari 2001
  • Laatst online: 14-06-2025

Varienaja

Wie dit leest is gek.

Niet zo lang geleden heb ik een eigen DAL gemaakt, maar sinds een maand of twee ben ik helemaal over naar hibernate. Ik zou niet weten waarom je zelf je DAL wilt maken, maar goed. De DAL die ik zelf had werkte met een visitor pattern.

De objecten zelf hadden geen kennis van persistentie, alleen de visitors hadden dat. Je krijgt dan zulke code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public Beest {
   int aantalpoten;
   Kleur kleur;

   public visit(Visitor v) {
      v.visit(this);
   }
}

public Kip extends Beest{
  int aantalveren;
}

public Visitor {
}

public Comitter extends Visitor {

   public void visit(Beest beest) {
      //sla het beest op
   }

   public void visit(Kip kip) {
      //sla de kip op
   }

}

public int main() {
   Kip k = new Kip();
   kip.visit(Comitter); //de kip wordt opgeslagen in de database.
}


En zo kan je ook een Deleter object implementeren, etc.

Siditamentis astuentis pactum.


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 11:11

alienfruit

the alien you never expected

Je zou kunnen kiezen voor dynamische SQL queries zodat het wordt gemaakt onafhankelijk van de database die moet worden aangesproken, oftewel de DAL verzint de correct query voor SQL Server, Oracle etc. Ik vind dit altijd heerlijk werken onder .NET.

  • RSchellhorn
  • Registratie: Augustus 2001
  • Laatst online: 02-05 20:03
Sja waarom een eigen DAL maken? Ik vind dat je iets zelf gewoon een keer gemaakt moet hebben om de achtergrond te snappen, welke problemen krijg je met concurrent users, waarom zus wel, maar zo niet...
Voor "echte" programma's kan je natuurlijk beter een O/R mapper pakken, want die zullen betere performance leveren, of in ieder geval veel sneller inzetbaar zijn.

Een eigen DAL kan natuurlijk wel voordelen hebben boven welke O/R mapper dan ook, want je hebt zelf alles in de hand. Zo wil ik hier ook naar file kunnen schrijven, wellicht dat met een goede DAL en implementatie van het factory pattern ik nu niks aan mijn BOL hoef te veranderen.

Waarom je een visitor pattern zou willen gebruiken weet ik niet, alleen voor create en update zou dit makkelijk kunnen zijn als je enorm complexe objecten hebt, die veel referenties naar andere business objecten hebt wellicht. In mijn geval zeker niet aan de orde, er wordt maar een object tegelijk bewerkt.

Als je een delete visitor nodig hebt, staan naar mijn mening de integriteit regels van je database niet goed, want volgens mij kan dat heel goed dmv een cascade delete.

"Ik heb zo veel soep gegeten, dat kan een mens niet aan. Ik heb zo veel soep gegeten, kan bijna niet meer staan. Ik zat daar maar te slurpen achter die grote kop en als ik bijna klaar was, dan schepten ze weer op!" (Hans Teeuwen)


  • RSchellhorn
  • Registratie: Augustus 2001
  • Laatst online: 02-05 20:03
alienfruit schreef op zaterdag 21 mei 2005 @ 13:39:
Je zou kunnen kiezen voor dynamische SQL queries zodat het wordt gemaakt onafhankelijk van de database die moet worden aangesproken, oftewel de DAL verzint de correct query voor SQL Server, Oracle etc. Ik vind dit altijd heerlijk werken onder .NET.
Volgens mij regelt je database driver voor Java dat zelf, als je ansi sql als query opgeeft zal een PreparedStatement dit naar native sql compileren voor je DBMS.

"Ik heb zo veel soep gegeten, dat kan een mens niet aan. Ik heb zo veel soep gegeten, kan bijna niet meer staan. Ik zat daar maar te slurpen achter die grote kop en als ik bijna klaar was, dan schepten ze weer op!" (Hans Teeuwen)


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:00
ReallyStupidGuy schreef op zaterdag 21 mei 2005 @ 11:07:
Toch zijn stored procedures hiervoor wel een oplossing, bovendien kun je als je het grondig aanpakt de beveiliging van je database optimaliseren (rechten op stored procedures ipv tabellen).
Mjah, SP's zijn niet altijd zaligmakend. Denk maar aan queries met een dynamische where clausule.
Waarom zijn rechten op SP's beter dan rechten op je tabellen ? Het enige voordeel dat je ermee hebt, is dat alle toegang dan via de SP's moet gebeuren.

Storede procedures zijn imo niet evel, ms-access is evil![/]
Waarom is Access evil ?
Ik weet niet hoe ms-access werkt met stored procedures maar als het idee gelijk is dan zou het herschrijven niet zo moeilijk moeten zijn, voornamelijk syntax en dan nog wat dingen die mysql misschien niet kan wat access wel kan.
Heeft MySQL wel stored procedures ?
Access heeft alleszins geen 'echte' stored procedures.

[ Voor 5% gewijzigd door whoami op 21-05-2005 15:51 ]

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:00
Slayer08 schreef op zaterdag 21 mei 2005 @ 14:17:
[...]


Volgens mij regelt je database driver voor Java dat zelf, als je ansi sql als query opgeeft zal een PreparedStatement dit naar native sql compileren voor je DBMS.
Als je een beetje van een applicatie maakt, heb je vrijwel nooit 'genoeg' aan de (beperkte) ANSI SQL.

MIsschien heb je hier trouwens nog wat aan:
[rml][ .NET|C#] Opzetten van een DAL[/rml]
[rml][ Patterns] PoEAA - TableModule + TableDataGateway[/rml]

[ Voor 19% gewijzigd door whoami op 21-05-2005 15:44 ]

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:00
Varienaja schreef op zaterdag 21 mei 2005 @ 13:21:
Niet zo lang geleden heb ik een eigen DAL gemaakt, maar sinds een maand of twee ben ik helemaal over naar hibernate. Ik zou niet weten waarom je zelf je DAL wilt maken, maar goed. De DAL die ik zelf had werkte met een visitor pattern.
Ik zie eerlijk gezegd niet direct het voordeel in om hier een visitor te gaan gebruiken ?
Waarom bv niet gewoon doen:

code:
1
2
3
4
5
Customer myCustomer = customerProvider.NewCustomer();

myCustomer.Name = "bliep";

customerProvider.Save (myCustomer);

Ik bedoel maar: het resultaat is hetzelfde, maar het is directer.
Ik zie het voordeel niet in om hier met een double dispatch te gaan werken; mijn business object weet ook helemaal niets af van 'hoe' hij gesaved of gecreeërd moet worden; dat doet m'n 'Provider'.

https://fgheysels.github.io/

Pagina: 1