Реализация 1 к n, отображающемуся для C++ ORM

Я пишу проект, где я должен реализовать разделенный вниз версия решения ORM в C++. Я поражен в реализации 1-n отношения для того же.

Например, если следующее является классами:

class A
{
    ...
}

class B
{
    ...
    std::list<A> _a_list;
    ...
}

Я обеспечил, загружают/сохраняют методы для загрузки/сохранения в дб. Теперь, если я беру случай B и следующего рабочего процесса:

  • 1 запись от _a_list удалена
  • 1 запись от _a_list изменяется
  • 1 запись добавляется к _a_list

Теперь, я должен обновить дб с помощью чего-то как "b.save ()". Так, что было бы лучшим способом сохранить изменения, т.е., определить дополнения, удаления и обновления _a_list.

5
задан Jonathan Leffler 4 April 2010 в 03:28
поделиться

4 ответа

Одна из стратегий - использовать перечисление для представления «статуса» записи. Т.е.

enum RecordState {
    RECORD_UNMODIFIED,
    RECORD_NEW,
    RECORD_CHANGED,
    RECORD_DELETED
};

Вы должны присвоить каждой записи RecordState (по умолчанию RECORD _NEW / RECORD _UNMODIFIED, если необходимо), и при вызове Save () она выполнит соответствующее действие для каждой записи и сбросит их состояние на RECORD _UNMODIFIED. Удаления будут исключаться из списка по мере их обработки.

1
ответ дан 14 December 2019 в 08:52
поделиться

Моя первая идея заключалась бы в том, чтобы инкапсулировать все возможные операции с базами данных как объекты команд (шаблон команды). Таким образом, вы можете создать столько команд, сколько захотите, пока не вызовете метод Save () для обновления базы данных. Здесь вам нужно убедиться, что эти команды обрабатываются как транзакции. Быстрая реализация будет выглядеть примерно так:

Заголовок:

#include <vector>

using namespace std;

class B;
class Cmd;

class B
{
    private:
        vector<Cmd*> m_commands;
    public:
        void AddCmd( Cmd* p_command );
        void Save();
};

class Cmd
{
    protected:
        B* m_database;

    public:
        Cmd( B* p_database );
        virtual void Execute() = 0;
        virtual void Undo() = 0;
};

class InsertCmd : public Cmd
{
    private:
        int m_newEntry;
    public:
        InsertCmd( B* p_database, int p_newEntry );
        void Execute() { cout << "insert " << m_newEntry << endl; }
        void Undo()    { /* undo of insert */ }
};

Источник:

#include "DbClass.h"

void B::AddCmd( Cmd* p_command )
{
    m_commands.push_back(p_command);
}

void B::Save()
{
    for( unsigned int i=0; i<m_commands.size(); i++ )
        m_commands[i]->Execute();
}

Cmd::Cmd( B* p_database ) : m_database(p_database)
{
    m_database->AddCmd(this);
}

InsertCmd::InsertCmd( B* p_database, int p_newEntry ) 
: Cmd(p_database), m_newEntry(p_newEntry)
{
}

Основной тест:

#include "DbClass.h"

int main()
{
    B database;
    InsertCmd  insert( &database, 10 );
    database.Save();

    return 0;
}
3
ответ дан 14 December 2019 в 08:52
поделиться

Record status is indeed a good idea.

I suggest that either:

(a) the app keeps deleted objects in the arrays and they are actually removed only when the ORM-like code is called to do a save (which is when it does INSERTs, UPDATEs and DELETEs)

OR

(b) the ORM context needs to maintain internally a behind-the-scenes list of all objects that have either been SELECTEDed from disk or created in RAM for each database transaction (or if not using transactions, connection). This list is iterated when the ORM is asked to save and INSERTs, UPDATEs and DELETEs are based on this list.

In the second case, you often find an additional requirement to be able to dissociate/detach an object from the ORM in some parts of the system, to create a persistent snapshot of a state or a modified version of an object that (according to some high level data flow model or other) is not immediately for storage, so an extra bit or enum state is desirable to reflect detachment. You may wish to be able to reassociate/reattach an object with an ORM transaction but note that there may be integrity issues involved here that if they need handling must be handled, and the method for handling them is often application specific.

Note that freshly created objects that are deleted before their first save should not generate a SQL DELETE hence an enum with UNMODIFED, NEW, CHANGED, DELETED is in practice often not enough, you also need NEW_DELETED and if going along with my theories DETACHED.

1
ответ дан 14 December 2019 в 08:52
поделиться

Немного поздно, но, на мой взгляд, вам понадобится Unit Of Work . Ваш текущий дизайн похож на реестр , который прекрасно работает с UoW.

1
ответ дан 14 December 2019 в 08:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: