Datenbank für C++


  • Administrator

    @Leon0402 Meinst du mit JSON modul jenes von SQLite? Das verwendest du nicht in C. Diese Funktionen sind nachher im SQL verfügbar. Also kannst du z.B. das machen:

    SELECT json_extract(value, '$.property.other') FROM document_store WHERE key = 'key';
    

    Das Resultat ist dann ein String, was im JSON Dokument unter property -> other lag. Wenn du dann in deinem Code mit JSON arbeiten willst, brauchst du eine JSON Bibliothek. Da findest du einige hier: https://json.org/ (unten)

    Eine mögliche moderne Implementierung: https://github.com/nlohmann/json



  • @Leon0402 Hi, wenn's für dich zum üben ist, die sqlite c-Api ist nicht so kompliziert, da kann man ganz gut einen eigenen Wrapper für schreiben. Ansonsten, wenn du einen guten Lightweight Wrapper findest, würden mich deine Erfahrungen damit interessieren. Wir verwenden gerade auch ein Wrapper der aus dem Umfeld eine Gui Bibltiothek stammt (wxWidgets und wxSSLite3), aber eigentlich möchten wir mittelfristig die wxWidgets Abhängigkeiten weg haben.
    Daher würde ich auch zur Vorsicht bei dem QT Wrapper raten, dann hängst du nämlich von QT ab und wenn das "nur" für die Datenbank Schnittstelle ist, ist das schon ein Klotz.
    Aber auch hier gilt, wenn das eh nur für dich ist und du evt. sogar schon QT benutzt, spricht auch da nichts gegen.



  • @Schlangenmensch Hab ich sogar schon mal sehr rudimentär gemacht, wurde im C++ Programmierer behandelt.
    Ja das ist so eine Sache mit den Abhänigkeiten ... Ich verwende sowieso schon QT libs, daher ist das nicht direkt das Problem (wobei eine unabhängige lib natürlich grundsätzlich besser ist, damit ich mir für nicht qt projekte nicht eine andere Suchen muss). Ich muss aber zugeben, dass mir natürlich zusagt, dass es z.B. von qt dann auch direkt ein sql model gibt. Das heißt es ist ziemlich einfach und schick seine Daten dann darzustellen in qml (oder qt widgets).



  • Ich kram mal meinen eignen Thread raus, da ich mal in der Zwischenzeit etwas mit Datenbanken experimentiert habe und mich nun doch wieder die Zweifel einholen 😃

    Diesmal mal ein konkretes Übungs Projekt, für das ich gerne eine Datenbank implementieren würde:

    • Cross Plattform Rezepte App (Linux/Windows/Mac Os, Android / iOS)
    • Es soll einen Server geben fürs synchronisieren, teilen etc. geben
    • Rezepte sollen flexibel und erweiterbar sein ... d.h. optionale Attribute wie Video, Tags etc. sind denkbar

    Nach den Empfehlungen hier, habe ich mal zu Sqlite gegriffen. Einerseits weil es recht kompakt ist und weil es quasi überall läuft.

    Dazu habe ich mich entschieden, das json plugin zu nutzen. Gründe dafür waren, dass ich dachte, es würde sich besser eignenen als klassische Tabellen. Unter anderem, weil die Rezepte ja doch variieren können und man so flexibler ist und weil man Rezepte dann direkt so an den Server senden bzw. vom Server empfangen könnte. Etwas zweifle ich da grade schon dran.

    Aber erstmal meine Implementierung:

    Zunächst die Tabelle

    query.exec("CREATE TABLE IF NOT EXISTS Recipes (name varchar(20) PRIMARY KEY, recipe json)")
    
    namespace {
    void static initDatabase();
    void static syncRecipeToDatabase(const Recipe& recipe);
    void static removeRecipeFromDatabase(const std::string& name);
    std::optional<Recipe> static findRecipeInDatabase(const std::string& name);
    std::vector<Recipe> static getRecipesFromDatabase()
    }
    

    So erstmal das Interface, um direkt auf die Datenbank zugreifen zu können.

    Hier mal zwei Implementierungen, die ich mit der nlohman json lib und Qt gemacht habe:

    void static syncRecipeToDatabase(const Recipe& recipe) {
        QSqlQuery query;
    
        query.prepare("INSERT OR REPLACE INTO Recipes (name, recipe) VALUES(:name , json(:recipe))");
        query.bindValue(":name", QString::fromStdString(recipe.getName()));
        query.bindValue(":recipe", QString::fromStdString(static_cast<nlohmann::json>(recipe).dump()));
        if(!query.exec()) {
            std::cout << query.lastError().text().toStdString() << std::endl;
        }
    }
    
    std::optional<Recipe> static findRecipeInDatabase(const std::string& name) {
        QSqlQuery query;
    
        query.prepare("SELECT * FROM Recipes WHERE name = :name");
        query.bindValue(":name", QString::fromStdString(name));
        if(!query.exec()) {
            std::cout << query.lastError().text().toStdString() << std::endl;
        }
    
        if(!query.next()) {
            return std::nullopt;
        }
    
        return nlohmann::json::parse(query.value(1).toString().toStdString()).get<Recipe>();
    }
    

    Mal abgesehen davon, dass diese Konvertierungen von string zu QString etc. etwas nerven, klappt das ganz gut.

    Dann hatte ich mir noch überlegt, dass man ja caching einführen könnte, damit man nicht immer sofort auf die Datenbank zugreifen muss.

    Dazu habe ich folgendes in meinem ReciperManager:

        constexpr static std::size_t RECIPE_MEMORY_SIZE = 10;
    
        std::deque<Recipe> recipeMemory;
    

    Und entsprechende Methoden auf die dann der Rest der Applikation zugreift, sehen z.B. so aus:

    void RecipeManager::addRecipe(const Recipe& recipe) {
        // If memory is full sync oldest recipe in the memory to the database and then remove it
        if(recipeMemory.size() == RECIPE_MEMORY_SIZE) {
            syncRecipeToDatabase(recipe);
            recipeMemory.pop_front();
        }
    
        recipeMemory.push_back(recipe);
    }
    
    Recipe* RecipeManager::findRecipe(const std::string& name) {
        // Check whether recipe is already in memory
        auto recipeIterator = std::find(recipeMemory.begin(), recipeMemory.end(), name);
        if(recipeIterator != recipeMemory.end()) {
            return &(*recipeIterator);
        }
    
        // Check whether recipe is in database
        auto recipe = findRecipeInDatabase(name);
        if(!recipe.has_value()) {
            return nullptr;
        }
    
        // Add found recipe to memory and return a pointer
        addRecipe(recipe.value());
        return &(recipeMemory.back());
    }
    

    Fragen zu der jetzigen Implementierung:

    • Ergibt mein Database Interface Sinn?
    • Ist das mit dem caching eine gute Idee? Bringt das was, macht man das so?
    • Kann man da was verbessern?

    Generell stelle ich mir die Frage, ob json hier der richtige Weg ist. Was ist z.B. wenn ich dann in meiner App eine Such Funktion habe ... dann suche ich ja mit bestimmten Parametern z.B. Name, Tags (wie vegetarisch), Kosten und erwarte eig. das ich ne Liste zurückbekomme mit Namen der Rezepte und Bild oder so. Halt das, was ich in meiner Ergebnisliste dann anzeige.
    Mit klassischem SQL könnte ich da ja relativ performant komplexe Suchanfragen durchführen ... bei json wäre ich mir da jetzt nicht mehr so sicher.
    -> Vor allem, wenn ich sqlite auf dem server verwende, ist performance ja nicht ganz unwichtig

    Insgesamt habe ich das Gefühl, dass ich einfach keine Ahnung von dem ganzen Thema habe und würde eig. mir gerne etwas Grundwissen aneignenen anstatt euch komplett auszufragen 😃 Es gibt zwar Bücher darüber, wie man jetzt ein SQL Layout macht oder das interface von sql benutzt, aber was mich viel mehr interessiert sind Sachen wie:

    • Embedded Database -> Wie integriere ich sqllite am besten in meine Software (oben ist ja mal ein Versuch ^^) ... macht ein mapping zu echten Objekten Sinn?
    • Caching (oben auch ein Versuch)
    • Wie syncronisiere ich am besten

    ... Also mehr das große ganze drum herum. Wie ich dann konkret sqlite benutze, kann ich mir dann angucken, wenn ich mir erstmal sicher bin, dass es überhaupt die richtige Wahl ist 😃

    Gibt es da Empfehlungen?

    Danke euch schon mal für die Hilfestellung. Ich habe da ja doch schon eine riesige Anzahl an Fragen 😃



  • @Leon0402

    Generell stelle ich mir die Frage, ob json hier der richtige Weg ist.

    Ach



  • @manni66
    Danke für die hilfreiche Antwort 😃 Ich habe ihr schon gemerkt, dass sql im allgemeinen nosql vorgezogen wird. Hat bestimmt auch seine Gründe und mit ein bisschen Erfahrung, werde ich mir da wohl auch noch eine Meinung zu bilden können.
    Am Anfang lässt man sich eben schnell mal vom Trend mitreißen 😵 Ich bitte um Nachsicht



  • Sehr spannendes Thema, aber bitte in einem anderen Thread.


  • Mod

    @Leon0402 sagte in Datenbank für C++:

    Sehr spannendes Thema, aber bitte in einem anderen Thread.

    Die hier nicht mehr sichtbare Diskussion findet man nun hier:
    https://www.c-plusplus.net/forum/topic/351066/ständig-wachsende-komplexität-im-programmiereralltag-fork-aus-datenbank-für-c/9


Anmelden zum Antworten