ORM scheitert gefühlt im Ansatz

M

Mart

Gast
Also ich versuch jetzt eine Zweite Bibliothek zu schreiben der einzige sinn von dem Sollte es sein im moment ein einfaches Select zu bauen möglichst ohne strings

Grund dafür ist es ... ich musste in Laravel einen tabellen namen ändern und einen Controller umbenennen es war einfach eine Katsatrophe... gefühlt "good luck finde die strings" es kann doch net sei dass alles nur über strings funktioniert ?

Ich hättte jetzt einen ansatz über enums versucht um mal Typos zu vermeiden und den String quatsch ,ich weis man kann tabellen hardcoden ewil sie sich realtiv wenig oft vom Tabellen namen ändern aber wenn sie sich ändern und man alle strings finden muss spürt man wie verzweiflung durch den Körper fließt...
z.b. ich hab nur eine einzelne Tabelle , der Enum name ist der tabellen name, die werte sind die Spalten namen
Java:
public enum User {
  NAME,PASSWORD;
}
jetzt ist das ziel ein einfaches Statement zu bauen
select * hab ich mal gehört dass man es nicht verwenden sollte ... und im plsql editor ist es die einzige autovervollständigung die immer funktioniert dass man diese auflöst in alle Spalten namen alsoooooo gibts für mich den spezial fall nicht

jetzt ist es ziel das zu erreichen, das füllen des prepared Statements seh ich im moment auch noch nicht als mein Problem :D
Java:
    PreparedStatement statement = new Statement<User>()
    .SELECT(User.NAME, User.PASSWORD)
    .FROM(User.class)
    .QUERY();
soweit so gut :D

jetzt zu dem Problematischen

ich habe es mit einer FluentApi oder Builder API umgesetzt ... keine ahnung ist (denke ich ) auch nicht wichtig
wo ich einfach mal den select buaen will und über query "theoretisch" das statement ausgeben will
Java:
public interface FLuentSQL {
 
  interface SELECTOR<ROW extends Enum<?>> {
     EXECUTOR SELECT(ROW... rowsToSelect);
  }

  interface EXECUTOR {
    void QUERY();
  }
}
die Implementation wäre hierbei dann die Statement Klasse

Java:
public class Statement<ROW extends Enum<?>> implements FLuentSQL.SELECTOR<ROW>, FLuentSQL.EXECUTOR {
  private StringBuilder statement = new StringBuilder();

  public Statement () {
    
  }
  @Override
  public void QUERY() {
    System.out.println("QUERY => "+statement);
    
  }

  @Override
  public Statement<ROW> SELECT(ROW... rowsToSelect) {
    if(rowsToSelect == null || rowsToSelect.length == 0)
      throw new RapidfxRuntimeException("Rows sind grampf");
    var selection = new SelectionStatement();
    selection.createSelectionStatement(rowsToSelect);
    statement.append(selection.get());
    return this;
  }
}
diese sollte einfach die Teile von select from where zusammen basteln

die statement Teile kann ich ja aufteilen


Java:
public abstract class StatementPart {
  protected StringBuilder statement = new StringBuilder();
  public abstract String get();
}
und das select statement
Java:
public class SelectionStatement<ROW extends Enum<?>> extends StatementPart {


  public String get() {
    return statement.toString();
  }

  public void createSelectionStatement(ROW... rowsToSelect) {
    statement.append(DBPART.SELECT);
    statement.append(space());
    appendExtraSelection(rowsToSelect);
  }

  private String space() {
    return " ";
  }

  private void appendExtraSelection(ROW... rowsToSelect) {
    var firstRow = rowsToSelect[0];
    appendSelection(firstRow);
    for (int i = 1; i < rowsToSelect.length; i++) {
      var nextRow = rowsToSelect[i];
      statement.append(" , ");
      appendSelection(nextRow);
    }
  }

  private void appendSelection(ROW rowsToSelect) {
    var firstRow = Objects.requireNonNull(rowsToSelect);
    if (firstRow != null) {
      statement.append(firstRow);
    }
  }
}

und das selection statement ist ein teil des trauer spiels , ich weis nicht wie ich es sonst zusammen bauen sollte ohne strings bzw maximal wenig strings , wie kann ich davon weg kommen?

ich weis nicht wie ich die leerzeichen und die Kommas und den Aufbau umändern kann
im prinzip ist der select immer gleich
Java:
SELECT
leerzeichen
arg1
komma
arg2

bzw
SELECT
leerzeichen
arg1
es gibt nur diese zwei fälle wenn man die spezial fälle mit count min und max weg lässt
 

Oneixee5

Top Contributor
Grund dafür ist es ... ich musste in Laravel einen tabellen namen ändern und einen Controller umbenennen es war einfach eine Katsatrophe... gefühlt "good luck finde die strings" es kann doch net sei dass alles nur über strings funktioniert ?
Man hätte auch einfach für den alten Tabellennamen ein Synonym erstellen können, dann funktionieren alles DML-Befehle weiterhin und man muss keinen SQL-Code ändern.
 
M

Mart

Gast
Was willst du denn für Tabellennamen statt Strings verwenden, Nummern?
die klassen namen

wenn ich zb in sql den select hab
Java:
SELECT * FROM User.class
und die user tabelle umbenennt ändern sich auch die "strings" und der sql befehl funktioniert immernoch


will ja den grundansatz soweit weg von strings machen wie geht... ansonsten kann ich lgeich die fertigen libs hernehmen
 

Oneixee5

Top Contributor
ansonsten kann ich lgeich die fertigen libs hernehmen
Was hast du gegen JPA? Das ist bestimmt sinnvoller als etwas Eigenes zu entwickeln und zu warten. Dein Ansatz bringt ja auch überhaupt keine Verbesserung. Wenn die Anwendung irgendwo läuft, dann musst die sie erst neu kompilieren und deployen. Eine Anpassung zur Laufzeit oder durch Konfiguration und Neustart ist so nicht möglich. Der Punkt ist: Ein DB-Schema kann nicht so geändert werden, dass es zur vorherigen Version inkompatibel ist. Andernfalls muss man Programmversion und DB-Version aneinander koppeln können. In deinem Fall ist das aber nicht möglich, da mehrere Anwendungen dieselbe DB nutzen. Du kannst deine Infrastruktur voneinander entkoppeln und schaffst standardisierte und versionierte Schnittstellen oder du veränderst das Schema nur so, dass es kompatibel bleibt.
 

Robert Zenz

Top Contributor
Der Nachteil von ORM ist immer "Duplikation". Ich habe Tabelle "A" mit Spalten "A1", "A2", und "A3", und ich brauche eine *exakte* Kopie davon als Java-Objekt. Aendere ich die Tabelle, muss ich auch das Objekt aendern, aendere ich das Objekt habe ich vorher die Tabelle geaendert.

Loesungen hier fuer gibt es viele, die reichen von "wenn du dein Datenmodell nicht abtippen kannst ist es ohnehin zerbrochen" ueber "wir generieren mit unseren Bibliothek Code" und "wir generieren mit unserer Bibliothek Klassen und fertig jars" direkt hinueber zu "wir generieren Datenbanken aus Klassen". Welcher dieser Ansaetze der eine richtige um alle Probleme zu loesen ist, darf jeder fuer sich selbst entscheiden. Die Wahrheit wird, wie immer, im Pragmatismus liegen, "verwende was auch immer es dir erlaubt dein Projekt fertigzustellen". Ich meine das wirklich so, was auch immer es einem erlaubt das Projekt fertigzustellen, was auch immer im Projekt funktioniert, sollte gemacht werden. Aber man sollte nicht der Illusion unterliegen dass es eine Allheillmittel ist, und im naechsten Projekt wieder so gut laufen wird.

An dieser Stelle wieder eine Warnung, ich bin ein alter Mann und ich haette gerne dass ihr euch alle von meinem Rasen verzieht...also ab hier weiterlesen auf eigene Gefahr weil "extreme" Meinungen kommen und, stelle ich gerade fest, tippe etwas viel, ich bitte um Verzeihung, aber ich musste mir da gerade von der Seele tippen, es war mir ein Beduerfnis.



Der Klassiker

Das klassische ORM bedeutet du hast eine Tabelle, du hast ein Zugriffsobjekt und du hast eine Klasse welche diese Tabelle widerspiegelt.

SQL:
create table CUSTOMERS (
    ID integer primary key generated by default as identity,
    NAME varchar(1000) not null,
    ADDRESS varchar(1000) not null,
    ZIP_CODE varchar(5) not null,
    CITY varchar(1000) not null,
    IBAN varchar(32) not null,
    BLOCKED boolean not null default false,
    CREATED_AT timestamp with timezone not null default CURRENT_TIMESTAMP,
    UPDATED_ATtimestamp with timezone
)

Java:
public class Customer {
    private int id;
    private String name;
    private String address;
    private String zipCode;
    private String city;
    private String iban;
    private boolean blocked;
    private OffsetDateTime createdAt;
    private OffsetDateTime updatedAt;
 
    public int getId() {
        return id;
    }
  
    public String getName() {
        return name;
    }
  
    public String getAddress() {
        return address;
    }
  
    public String getZipCode() {
        return zipCode;
    }
  
    public String getCity() {
        return city;
    }
  
    public String getIban() {
        return iban;
    }
  
    public boolean isBlocked() {
        return blocked;
    }
  
    public OffsetDateTime getCreatedAt() {
        return createdAt;
    }
    public OffsetDateTime getUpdatedAt() {
        return updatedAt;
    }
  
    public void setId(int id) {
        this.id = id;
    }
  
    public void setName(String name) {
        this.name = name;
    }
  
    public void setAddress(String address) {
        this.address = address;
    }
  
    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }
  
    public void setCity(String city) {
        this.city = city;
    }
  
    public void setIban(String iban) {
        this.iban = iban;
    }
  
    public void setBlocked(boolean blocked) {
        this.blocked = blocked;
    }
  
    public void setCreatedAt(OffsetDateTime createdAt) {
        this.createdAt = createdAt;
    }
  
    public void setUpdateAt(OffsetDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
}

public class Customers {
    public Customer getCustomer(int id) {
        // TODO
    }
  
    public List<Customer> getCustomers() {
        // TODO
    }
}

Vorteil ist klar, du verwendest Klassen und kannst dich nie vertippen. Nachteile sind das du viel tippen musst, du musst die Struktur duplizieren und du musst noch mehr tippen fuer die Zugriffsobjekte. Wenn du die Resktriktionen von der Datenbank abbilden willst, zum Beispiel Feld-Laenge, kommt noch mehr Tipparbeit dazu.

Meiner Meinung nach zum in die Tonne klopfen weil das einfach viel zu teuer ist und nicht gut skaliert (10.000 Tabellen mit hunderten Spalten pro Tabelle?). Es sei denn deine Datenbank ist austauschbar und aendert sich regelmaeszig und dein Java-Modell ist die einzige Wahrheit (habe ich in 14 Jahren ERP Systeme kein einziges mal gesehen).

Wir tippen nicht, wir lassen tippen!

Dann gibt es den klassischen Ansatz nur mit "wir tippen fuer dich!" Loesung. Also alles was du oben siehst wird generiert auf die ein oder andere Art und Weise. Da gibt es jetzt zwei Richtungen, je nachdem was die Quelle der Wahrheit ist, die Datenbank oder das Java-Modell.

In beiden Faellen ist der Vorteil klar, du bekommst Sicherheit und musst das ganze Konvolut nicht tippen. Die Nachteile sind dass die Generierung bei Aenderungen aufgerufen werden muss (vermutlich haendisch). Desweiteren tendieren automatische Konvertierungen, insbesondere von komplexen Beziehungen, zu einem sehr groszen "Was zum Geier?!"-Faktor. Man muss also vermutlich wieder in die Generierung auf die ein oder andere Art und Weise wieder eingreifen damit es wenigstens halbwegs sauber wird. Und dann sind da Updates, was passiert wenn du die Struktur der Wahrheit aenderst? Wenn die Richtung Datenbank zu Java ist, ist die Antwort einfach. Wenn die Richtung Java zu Datenbank ist, nicht mehr so sehr.

Meine persoenliche Meinung ist "Wenn du Klassen generieren laesst (in Massen), hat jemand etwas falsch gemacht". Weil das bedeutet dass du eigentlich gerne etwas technologisch geloest haettest, es aber niemand herausgefunden hat wie man so etwas loest, also nehmen wir die einfachste Loesung und die heiszt "Strings basteln und in Dateien schreiben".

Strings sind boese, wir verwenden nur Konstanten! *applaus*

Nehmen wir an wir haben rohe Abfragen.

Java:
ResultSet result = databaseConnection.execute("select ID, NAME, CITY from CUSTOMERS where UPDATED_AT is not null");

foreach (Row row : resultSet) {
    System.out.println(row.get("NAME"));
}

Jetzt klingelt vielen noch die Aussage vom Professor in den Ohren "(Magische) Strings sind boese! Es muss alles Konstanten sein!" also bauen sie so etwas:

Java:
public static final TABLE_CUSTOMERS = "CUSTOMERS";
public static final TABLE_CUSTOMERS_COLUMN_ID = "ID";
public static final TABLE_CUSTOMERS_COLUMN_NAME = "NAME";
public static final TABLE_CUSTOMERS_COLUMN_ADDRESS = "ADDRESS";
public static final TABLE_CUSTOMERS_COLUMN_ZIP_CODE = "ZIP_CODE";
public static final TABLE_CUSTOMERS_COLUMN_CITY = "CITY";
public static final TABLE_CUSTOMERS_COLUMN_IBAN = "IBAN";
public static final TABLE_CUSTOMERS_COLUMN_BLOCKED = "BLOCKED";
public static final TABLE_CUSTOMERS_COLUMN_CREATED_AT = "CREATED_AT";
public static final TABLE_CUSTOMERS_COLUMN_UPDATED_AT = "UPDATED_AT";

ResultSet result = databaseConnection.execute("select " + TABLE_CUSTOMERS_COLUMN_ID + ", " + TABLE_CUSTOMERS_COLUMN_NAME + ", " + TABLE_CUSTOMERS_COLUMN_CITY + " from " + TABLE_CUSTOMERS + " where " + TABLE_CUSTOMERS_COLUMN_UPDATED_AT + " is not null");

foreach (Row row : resultSet) {
    System.out.println(row.get(TABLE_CUSTOMERS_COLUMN_NAME));
}

Was natuerlich komplett am Ziel vorbei ist. Vorteil ist wieder, du kannst dich nicht vertippen auszer in den Werten, und sehen wir's ein, bei dem Copy&Paste wird ein Vertipper dabei sein den du nicht so schnell bemerkst. Nachteile sind wieder du musst die Struktur duplizieren, und dein Code wird perfekt unleserlich. Da habe ich dann ja lieber nur die rohen Strings, weil die kann man wenigstens lesen und ich weisz welche Tabelle in execute("select * from CUSTOMERS")[ICODE] mit einem Blick, in [ICODE]execute("select * from " + MAIN_CUSTOMER_TABLE_NAME) kann ich davon ausgehen dass sich niemand vertippt hat...merken werde ich es aber erst zur Laufzeit, wenn ueberhaupt.

Natuerlich sind magische Strings boese, aber damit sind eben nur *magische* gemeint. String-Konstanten deren Wert sich unter Umstaenden mal aendern wird. Zum Beispiel:

Java:
myCoolLibrary.setFeature("com.mycoollibrary.somemodule.feature.ON");

Koennte natuerlich sein dass sich die Konstanten irgendwann mal aendert (weil das Feature umgezogen ist, oder refactoring oder so), also waere es viel besser wenn das von Haus aus in einer Konstante liegt:

Java:
myCoolLibrary.setFeature(FEATURE_ENABLED);

Dann muss der Benutzer der Bibliothek nie wieder darueber nachdenken. Besser.

Wohingegen dass genau Null hilft, ist wenn der String sich nicht aendert oder wenn er von Haus aus als fluechtig oder nicht relevant angesehen werden sollte. Ersteres waeren Tabellennamen, wie oft aendert sich ein Tabellenname in einer Produktivumgebung? Nie, weil man legt eine neue Tabelle an und migriert die Daten in die neue Struktur, und das macht man nur wenn man ohnehin die Logik neu schreibt, ansonsten fasst man den nicht an (insbesondere wenn mehere Applikationen in die gleiche Datenbank greifen). Texte in Labels und anderen Steuerelementen sind perfekte Beispiele fuer Strings welche ohnehin unbestaendig sind:

Java:
greetingLabel.setText("Welcome to this Application!");

Klar kann man dafuer eine Konstante anlegen:

Java:
public class Text {
    public static final String GREETING_APPLICATION_TEXT = "Welcome to this Application!";
}

greetingLabel.setText(Text.GREETING_APPLICATION_TEXT);

Aber dadurch gewinnt man gar nichts, auszer das man nun nicht mehr einfach sehen kann welcher Text wo drinnen steht und dadurch die Orientierung im GUI Code schlechter wird (und sehen wir's ein, die war schon vorher nicht gut weil GUI Code..die Idee das GUI Code schoen wird kannst du gleich knicken).

Datenbank ist die Wahrheit, verzichten wir auf Schnickschnack.

Wenn wir annehmen dass die Datenbank die Wahrheit ist, und diese sich nicht "unabsehbar" veraendern wird, ist ein direkter Ansatz mit Strings nicht schlecht. Ganz im Gegenteil, es ist der mit am wenigsten Aufwand beim erstellen und mit Test-Abdeckung bekommt man auch Tippfehler einfach in den Griff. Um jetzt ein konkretes Beispiel auszugraben, JVx verwendet diesen. Also die Annahme ist dass die Datenbank unabhaengig von der Applikation ist, und die Datenbank auf jeden Fall laenger leben wird als die Applikation. Klassisches ORM kann man knicken weil die Datenbank in etwa 10.000 Tabellen mit teilweise hunderten Spalten umfasst, das ist nicht tragbar. Also hat man ein einfaches Datenzugriffs-Objekt welchem man nur den Tabellennamen sagt, und diese dann per Strings betritt. Zum Beispiel:

Java:
DataBook dataBook = new DataBook();
dataBook.setName("CUSTOMERS");
dataBook.open();

for (int index = 0; index < dataBook.getRowCount(); index++) {
    dataBook.setSelectedRow(index);
 
    System.out.println((String)dataBook.getValue("NAME"));
}

Jetzt ruempft natuerlich jeder erstmal die Nase, aber wir koennen hier zwei Annahmen treffen: Erstens, die Namen der Tabellen und Spalten werden sich nie aendern, und zweitens, der Code wird getestet. Damit ist das mitunter die einfachste Loesung. Der Nachteil ist dass man auf Java-Seite keine Typsicherheit beim kompilieren hat, also wenn du jetzt getValue("NAME") auf OffsetDateTime wandelst, wirst du das erst zur Laufzeit merken (da man den Code aber ohnehin testen muss...).



Als jemand der schon mit all diesen Ansaetzen gearbeitet hat, in alle Richtungen, man muss zuerst ueberlegen was man will:

* Was ist die Wahrheit (Datenbank oder Java-Modell)? Also quasi Master/Slave definieren.
* Wie gehe ich mit Aenderungen in der Wahrheit um?

Wenn du das mit "Datenbank und wenige" beantworten kannst, ist klassiches ORM ein recht guter Ansatz, nicht ideal, aber gut. Bei "Java und haeufig" wuerde ich weglaufen, weil genau so etwas habe ich einmal in einem Prototypen umgesetzt, und es nicht lustig wenn man unter der Annahme agiert dass alle Daten erhalten bleiben muessen. Bei "Datenbank und nie" kann man auch einen direkten Ansatz waehlen, wie JDBC direkt oder eben die JVx (aehnliche) Loesung, weil der Code wird sich nie wieder veraendern von der Datenbank-Seite aus.

Ich hoffe euch nicht allzu sehr gelangweilt zu haben, und wie gesagt, es war mir gerade ein Beduerfnis.
 

Robert Zenz

Top Contributor
und das selection statement ist ein teil des trauer spiels , ich weis nicht wie ich es sonst zusammen bauen sollte ohne strings bzw maximal wenig strings , wie kann ich davon weg kommen?
Gar nicht, bei Definition nicht. Deine Schnittstelle zur Datenbank ist SQL, und das ist ein String. Du musst deine Anbindung also so betrachten:

Code:
Java Modell <==> SQL-Wandler <==> Datenbank

Die Aufgabe von der Schicht zwischen deinem Modell und der Datenbank ist einzig und alleine Java-Objekte in SQL-Ausdruecke zu uebersetzen, und SQL-Ergebnisse wieder in Java-Objekte.

Ich verstehe dass du jetzt eine schlechte Erfahrung hattest (naemlich Spalten- oder Tabellennamen suchen in einer, vermutlich, nicht allzu uebersichtlichen Code-Basis), aber das solltest du jetzt nicht als Begruendung fuer einen religioesen Kreuzzug gegen jeden einzelnen String hernehmen.
 
M

Mart

Gast
Bei "Datenbank und nie" kann man auch einen direkten Ansatz waehlen, wie JDBC direkt oder eben die JVx (aehnliche) Loesung, weil der Code wird sich nie wieder veraendern von der Datenbank-Seite aus.
ich habe mal das ganze gelesen und ich denke ich werde davon ausgehen und mal in die richtung tendieren watscheln
zusätzlich geh ich davon aus dass ich single source of truth habe dh in meinem mvc quatsch den ich gebaut habe steht im model nur eine anfrage auf den server "mach mir ne select biddeschön" und der server baut dann die selects und führt aus also der client ist bei der ganzen problematik raus, dämliche anfragen werden abgelehnt :D


was ich ja ursprünglich wollte ist es die select anweisungen überhaupt zu bauen

ich werd ja einen Tod sterben müssen, da werd ich niemals drum rum kommen nur was ist der schönste ;)

jetzt angenommen ich habe dream code, und ich lauf immer in schmarn rein
Java:
Statement std = querier
    .SELECT("NAME","PASSWORT")
    .FROM(TABLES.USER)
    .WHERE()
        .equals("NAME")
        .nonNull("PASSWORT");

std.fuellen(1, "BOB");
std.fuellen(2,"xyz");

1. ich habe die Spalten namen als strings das ist ja das JVx problem, ich kann ins leere schießen , ich habe keine programmier warnung wenn ich bei den spalten namen typos drin habe ist blöd
2. jetzt löse ich das from über enums ich bin näher dran keine typos zu haben ist schon mal gut, wenn ich jetzt 10000 tabellen habe mit jeweils 100 spalten eg in orm 1000000 als kreuz produkt "klein getreten" ist unmöglich,den tod zu sterben in einem enum 10000 werte drin zu haben nur dass ich die typos "reduziere" geht noch ( ? ) , dass die Tabellen dann enums mit den spalten kriegen wird wahrscheinlich umfangreicher
3. gut da ist wieder das spalten problem mit den strings genauso wie bei den selects


weitere problem
ich bin jetzt mal ganz fancy und habe von jeder tabelle eine record klasse oder als orm, was passiert dann bei einem select von 2 tabellen? dann kann ich die tollen objekte in die tonne treten , wenn ich von den 2 tabellen die jeweils 10 spalten haben jeweils 1e selektiere, habe ich 2 ( ansich records ) wo 18 von 20 werten leer sind, von objekt in "validem" zustand denke ich nicht dass das zutrifft

was ist jetzt mit hash map ansatz... ja ich weis... man wirft ne hashmap auf das problem und gleich wirds toller :D

basierend auf dem Select bau ich die hashmap mit den keys, super dann ist das record problem "gelöst" ...
Java:
map.get("NAME");
map.get("PASSWORT");
tja wieder in das typo problem gelandet jetzt sind die spalten schon 2 mal als string da dh bei einer spalten namens änderung bin ich raus...

mit der was wäre wenn lösung ich lass beim start des programms die Datenbank den kompletten aufbau ausgeben und ich speichere den aufbau ab in

Java:
tableMap.(tableName als key, new HashMap ( ganze reihen namen als keys und wert ist leer ))

und davor schalte ich einen prüfer also table xyz if key existst in row => das programm schmiert bei einer umbenennung beim key prüfen ab und nicht in der DB IS JA SCHON MAL WAS... aber weuter weis ich auch net


ich kann ja auch
Java:
foreach ( value in Tables enum )
{
    get rows ...
}
somit hab ich bei einem durchlauf die "validierung" dass schon mal die Tabellen namen funktionieren das ist mal irgendwas ... bei laravel mit dem plural hab ich ne krise gekriegt.... also strings als tabellen namen hernehmen , die validierung der "existenz" der tabellen über den dateinamen der über datum eindeutig gemacht wird , und den Tabellen namen in den plural zu setzen und aus y ein ie zu machen ist eine pure katastrophe... und das sind NUR die tabellen namen also das ist ein grundproblem... wenn ich meine tabelle beschissen benenne sollte diese auch so bleiben wie ich sie genannt habe ist immerhin meine beschissen benannte tabelle da sollte keine "hintergrund magie" passieren die mir den namen durcheinander wirft
 
Zuletzt bearbeitet von einem Moderator:

Robert Zenz

Top Contributor
Wie ich bereits gesagt habe, die Frage ist was fuer ein Problem du genau loesen willst, und welche Rahmenbedinungen du hast, je nachdem wird die Loesung anders. Also du musst dir anschauen welchen Applikationstyp and Arbeitsablauf du abbilden willst, und kannst dann darauf optimieren anfangen bis du bei einer guten Loesung *dafuer* angekommen bist. Die ultimative dynamische Loesung wird es wohl nie werden, aber du kannst ja *einen* Fall perfekt abdecken.

was ist jetzt mit hash map ansatz... ja ich weis... man wirft ne hashmap auf das problem und gleich wirds toller :D

basierend auf dem Select bau ich die hashmap mit den keys, super dann ist das record problem "gelöst" ...
Java:
map.get("NAME");
map.get("PASSWORT");
tja wieder in das typo problem gelandet jetzt sind die spalten schon 2 mal als string da dh bei einer spalten namens änderung bin ich raus...

mit der was wäre wenn lösung ich lass beim start des programms die Datenbank den kompletten aufbau ausgeben und ich speichere den aufbau ab in

Java:
tableMap.(tableName als key, new HashMap ( ganze reihen namen als keys und wert ist leer ))
und davor schalte ich einen prüfer also table xyz if key existst in row => das programm schmiert bei einer umbenennung beim key prüfen ab und nicht in der DB IS JA SCHON MAL WAS... aber weuter weis ich auch net
Ja, das ist der komplette Ansatz wie im JVx Framework. Du hast quasi eine 2D-Map, nur heiszt die DataBook, und wenn es den Namen nicht gibt bekommst du zur Laufzeit dann den Fehler darueber. Bedeutet natuerlich dass der gesamte Code getestet sein muss, um diesen Fehler zu bemerken...aber das waere ja ohnehin besser beziehungsweise muss ohnehin passieren (wenn nicht automatisch dann mit jemandem der sich durchklickt nach definiertem Ablauf).

jetzt angenommen ich habe dream code, und ich lauf immer in schmarn rein
Java:
Statement std = querier
.SELECT("NAME","PASSWORT")
.FROM(TABLES.USER)
.WHERE()
.equals("NAME")
.nonNull("PASSWORT");

std.fuellen(1, "BOB");
std.fuellen(2,"xyz");
1. ich habe die Spalten namen als strings das ist ja das JVx problem, ich kann ins leere schießen , ich habe keine programmier warnung wenn ich bei den spalten namen typos drin habe ist blöd
2. jetzt löse ich das from über enums ich bin näher dran keine typos zu haben ist schon mal gut, wenn ich jetzt 10000 tabellen habe mit jeweils 100 spalten eg in orm 1000000 als kreuz produkt "klein getreten" ist unmöglich,den tod zu sterben in einem enum 10000 werte drin zu haben nur dass ich die typos "reduziere" geht noch ( ? ) , dass die Tabellen dann enums mit den spalten kriegen wird wahrscheinlich umfangreicher
3. gut da ist wieder das spalten problem mit den strings genauso wie bei den selects
1. Ja, das muss man in Kauf nehmen (und testen).
2. Korrekt, je groeszer die Anzahl an Tabellen, je groeszer der Enum, je wahrscheinlicher Copy&Paste Fehler. Da muss man sich dann fragen "Wenn ich schon die Spalten nur noch als Strings habe, wieso dann nicht auch die Tabellen?".
3. Genau.

Wobei die Struktur welche du hier beschreibst bereits einen groszen Vorteil hat: Sie kann Datenbankunabhaengig agieren. Also aus deinem querier kann je nach Implementierung dann SQL fuer unterschiedliche Datenbanken rausfallen. Also ob du dann PostgreSQL oder SQLite oder H2 verwendest spielt dann keine Rolle, der Java Code muss nicht mehr angepasst werden, was auch schon ein riesiger Vorteil ist weil dieser dann von der Datenbank entkoppelt ist. Das ist zum Beispiel auch praktisch bei Tests, weil du dann in Produktion zum Beispiel eine Oracle DB haben kannst, aber deine (lokalen) Tests von deiner Applikationslogik kannst du mit einer H2 fahren.

weitere problem
ich bin jetzt mal ganz fancy und habe von jeder tabelle eine record klasse oder als orm, was passiert dann bei einem select von 2 tabellen? dann kann ich die tollen objekte in die tonne treten , wenn ich von den 2 tabellen die jeweils 10 spalten haben jeweils 1e selektiere, habe ich 2 ( ansich records ) wo 18 von 20 werten leer sind, von objekt in "validem" zustand denke ich nicht dass das zutrifft
Das ist richtig, hatte ich gar nicht daran gedacht, mit einem "klassischen ORM" kannst du keine beliebigen Kreuzungsprodukte abfragen, du musst immer eine Klasse davon haben. Wenn du keine festen Klassen hast (JVx, Map, etc.) hast du das Problem nicht, weil da ist drinnen was drinnen ist (und du kannst die Spaltennamen immer noch validieren, weil du kannst ja die Metadaten vom Ergebnis-Set abfragen und weiszt dann welche Spalten mit welchen Typen darin sind).

ich werd ja einen Tod sterben müssen, da werd ich niemals drum rum kommen nur was ist der schönste ;)
Das ist so, ja, in jedem Projekt. Insbesondere in Projekten fuer welche du bezahlt wirst, weil deine Vorgaben damit immer von Aussen kommen und sich selten mit deinen perfekten Loesungen fuer diesen anderen aber aehnlichen Fall decken werden, damit muss man immer biszchen umbauen und Kompromisse eingehen, das ist Teil des Lebens.
 
M

Mart

Gast
mal weitere annahmen
wenn ich es so umsetze

Java:
enum Tables{
    USER(UserRow.values);
 
    Tables(ENUM[] enumArray)
}
enum userRow{
    Name,Passwort;
}
also ein enum enthält ein anderes

und es gibt die theoretische chekcer methode

Java:
check(Tables.values());

zuerst hol ich mir irgendwie alle tabellen namen raus dies gibt und deren spalten namen wie auch immer

dann
Java:
check(EnumTable)
foreach ( EnumTable )
{
    falls ( gefundene Tabellen enthalten tabellen namen )
    {
        vergleiche Spalten namen mit innere Enum werte
        falls irgendwas net passt warnung raus
    }
    ansonsten
    {
        warnung raus dass die Tabelle net gefunden wurde
    }
}
System.exit(0);
}
und somit latsch ich halt alle "enum Tables" durch ... muss ja nicht mal alles in eine packen, mehr als warnen "da stimmt was net mit den Typos musst ma gucken" kann ich als "bibliotheks" geber

gut ... dämliche situation ... ich hab 1000 tabellen... ich hab was geileres vor als 1000 enums zu erzeugen aber das könnte man mit einer erzeugungs methode erstellen ... also code der code schreibt

aber die arme sau möchte ich sehen die 1000 tabellen in einer anwendung benutzen muss :D

aber im prinzip ist es das gleiche prinzip wie ich es auch mit meinem mvc umgesetzt habe mit den attributen in der view und die suche ich im controller oder sonst wo .. nur dieses mal ohne annotationen
 

Oneixee5

Top Contributor
aber die arme sau möchte ich sehen die 1000 tabellen in einer anwendung benutzen muss
das ist doch höchstens Durchschnitt. In einem aktuellen Projekt sind 1229 Tabellen, 218 Views, 63 MViews, 16 Global Temp Tables, 57 Procedures, 37 Functions, 49 Package Bodies und 84 Object Types. Es werden über 3600 Datenbanken mit der dieser DB synchronisiert (In und Out). 6 Anwendungen haben direkten Zugriff auf die DB und es gibt eine Unzahl an Schnittstellen für externe Systeme. Wir arbeiten zu 5. auf der DB, eine Person wird gerade angelernt, 2 Vorgesetzte und 2 Muschkoten für die Entwicklung von Software. Wieviele Admins kann ich nicht sagen, das geht alles über Tickets. Die DB exsistiert seit 16 Jahren und ich bin von Begin an dabei, aber nicht ausschließlich, man soll sich ja schließlich nicht in einem Projekt ausruhen.
 
M

Mart

Gast
das ist doch höchstens Durchschnitt. In einem aktuellen Projekt sind 1229 Tabellen, 218 Views, 63 MViews, 16 Global Temp Tables, 57 Procedures, 37 Functions, 49 Package Bodies und 84 Object Types. Es werden über 3600 Datenbanken mit der dieser DB synchronisiert (In und Out). 6 Anwendungen haben direkten Zugriff auf die DB und es gibt eine Unzahl an Schnittstellen für externe Systeme. Wir arbeiten zu 5. auf der DB, eine Person wird gerade angelernt, 2 Vorgesetzte und 2 Muschkoten für die Entwicklung von Software. Wieviele Admins kann ich nicht sagen, das geht alles über Tickets. Die DB exsistiert seit 16 Jahren und ich bin von Begin an dabei, aber nicht ausschließlich, man soll sich ja schließlich nicht in einem Projekt ausruhen.
das mit einer anwendung war darauf bezogen dass du wahrscheinich diese 1200 tabellen nicht in eine einzige anwendung rein gebacken hast nehme ich mal an oder?
 

Robert Zenz

Top Contributor
gut ... dämliche situation ... ich hab 1000 tabellen... ich hab was geileres vor als 1000 enums zu erzeugen aber das könnte man mit einer erzeugungs methode erstellen ... also code der code schreibt
Aber dann hast du ja wieder das Gleiche, naemlich dass du die Datenstruktur haendisch tippen und duplizieren musst.

aber die arme sau möchte ich sehen die 1000 tabellen in einer anwendung benutzen muss :D
Ich bin mir sehr sicher mal eine Oracle DB mit 2000-3000 Tabellen gesehen zu haben (wird aber auch so 30 Jahre alt gewesen sein die Datenbank), und das war kein groszes Unternehmen (ich meine, schon groeszer, aber nicht grosz). Geschichten habe ich gehoert von Datenbanken die es auf meherere Zehntausend Tabellen gebracht haben. Wenn du von ein bis zwei Tabellen pro Feature in der Applikation ausgehst, bist du schnell bei mehreren hundert. Wenn du das dann noch ueber 20 Jahre machst...

das mit einer anwendung war darauf bezogen dass du wahrscheinich diese 1200 tabellen nicht in eine einzige anwendung rein gebacken hast nehme ich mal an oder?
Bei den ERP Loesungen die ich kenne, bekommen alle die gleichen Clients, also alles in einer Applikation (Rechte und sowas aussen vor).

...und 2 Muschkoten für die Entwicklung von Software.
Ist das eine gelaeufige Bezeichnung oder von dir?
 
M

Mart

Gast
Aber dann hast du ja wieder das Gleiche, naemlich dass du die Datenstruktur haendisch tippen und duplizieren musst.
die idee wäre ich hol mir irgendwie die db tabelle auf basis des namens raus mit den spalten namen

und bau mir dann einen file writer der nach dem format

Java:
enum TABELLENNAME {
    alle,spalten,namen;
}
enums erstellt oder sonst irgend einem format da muss ich nur den namen eintippen

es fallen aber auch nicht plötzlich 20000 tabellen vom himmel

bei jedem genannten beispiel würde halt ORM einfach nur versagen gefühlt, es ist unmöglich diese in kalssen abzubilden das ist gefühlt bei orm ein "dream case" wie bei dem lernen von der vererbung von reptilien und frosch und schlange... aber in der wirklichkeit muss man manchmal tiefer graben um eine sinnvolle vererbung heraus zu finden
 

Oneixee5

Top Contributor
bei jedem genannten beispiel würde halt ORM einfach nur versagen gefühlt, es ist unmöglich diese in kalssen abzubilden das ist gefühlt bei orm ein "dream case" wie bei dem lernen von der vererbung von reptilien und frosch und schlange... aber in der wirklichkeit muss man manchmal tiefer graben um eine sinnvolle vererbung heraus zu finden
ORM wird bei uns normalerweise aus der DB generiert, da ändern wir nur wenige Sachen, z.B.: Sequenzen oder wenn nötig Interfaces einbinden. Diese Eingriffe kann man bei manchen Generatoren auch abspeichern, so das man das nicht immer wieder tun muss. Ich sehe da nicht viele Fälle für sinnvolle Vererbung bei ORM. Die DB ist ja selbst auch eine Anwendung und muss weiter bestehen wenn sich eine Anwendung im Umfeld ändert.
 

Oneixee5

Top Contributor
die idee wäre ich hol mir irgendwie die db tabelle auf basis des namens raus mit den spalten namen

und bau mir dann einen file writer der nach dem format

Java:
enum TABELLENNAME {
alle,spalten,namen;
}
Das ist ja nur ein sehr einfacher Ansatz. Wie willst du mit FOREIGN KEY Constraint umgehen, also abhängigen Tabellen/Objekten?
 
M

Mart

Gast
ja der ansatz ist ungefähr auf kartoffel ebene

ich weis noch nicht mal welchen use case das abdecken soll, es kann von 2 selects und 1 insert bis hin zu allem sein, vllt wäre ja eine java <> sql vorbereiter <> plsql <> db sql verbindung besser dafür geeignet aber keine ahnung
 
M

Mart

Gast
da es irgendwie mit meinem frontend bibliothek zusammen passen sollte is es relativ schwer einen use case zu erstellen,da rapidfx von mir so ausgelegt wurde dass es maximal schwammig und frei ist dh im prinzip kann man alles darin verändern

jetzt irgend eine Verbindung vom frontend zum bakcend zu bauen ist relativ schwer
 

LimDul

Top Contributor
Was interessiert ein Frontend irgendwelche DB-Tabellen? Damit sollte ein Frontend - und auch ein Frontend-Framework nix zu tun haben. Das ist für die Darstellung der Daten zuständig
 
M

Mart

Gast
es ist auch ein "unabhöngiges" anderes projekt... vllt bin ich auch nur von laravel geshcädigt :D
wo einfach alles überall ist

es war ja eig geplpant dass in den models kein sql code oä drin steht sondern nur eine Anfrage an einen server der das macht
 

Robert Zenz

Top Contributor
So wie du das erzaehlst, bist du auf der Suche nach einer Loesung welche ein Problem sucht. Keine Frage, habe ich auch schon gemacht, aber es ist sher schwer etwas zu entwickeln ohne Ahnung zu haben fuer was. Vielleicht waere es besser du machst erstmal ein paar Applikationen, also kein "Hallo Welt" sondern wirklich Applikationen die du verwenden wuerdest. Dann hast du naemlich die Erfahrung und du hast etwas von wo aus du aufbauen kannst. Das hat den weiteren Vorteil dass du deine Bibliotheken direkt testen kannst und auch gleich siehst wenn sich die API zum Beispiel in eine schlechtere Richtung bewegt. Dabei musst du nur aufpassen dass Applikationsdetails nicht in deine Bibliothek rueberschwimmen.
 
M

Mart

Gast
meine rapidfx api hab ich ja in meinem studiums projekt testen können da da das einzige "backend" eine sqlite datenbank war und eine peer to peer verbindung für den multiplayer dh man war selber host... die frontent api zu bauen hat funktioniert die konnte ich auch testen
 
M

Mart

Gast
rapidfx hat halt "die probleme" gelöst in die ich rein gelaufen bin, vllt lass ich das jetzt mal auf sich beruhen, muss ja noch bei den system propertys rum spielen beim frontend

vorallem diesem preloader der maximal versteckt ist..
 

Ähnliche Java Themen

Neue Themen


Oben