为ormc+实现1到n映射+; 我正在编写一个项目,我需要在C++中实现一个精简版的ORM解决方案。我在为同样的目标实现1-n关系时感到震惊

为ormc+实现1到n映射+; 我正在编写一个项目,我需要在C++中实现一个精简版的ORM解决方案。我在为同样的目标实现1-n关系时感到震惊,c++,orm,mapping,C++,Orm,Mapping,例如,如果以下是类: class A { ... } class B { ... std::list<A> _a_list; ... } A类 { ... } B类 { ... 标准::列表_a_列表; ... } 我提供了加载/保存到数据库的加载/保存方法。 现在,如果我以B为例,并采用以下工作流: 从列表中删除1个条目 修改了列表中的1个条目 1个条目添加到_a_列表中 现在,我需要使用类似“b.save()”的东西来更新数据库。 那么,

例如,如果以下是类:

class A
{
    ...
}

class B
{
    ...
    std::list<A> _a_list;
    ...
}
A类
{
...
}
B类
{
...
标准::列表_a_列表;
...
}
我提供了加载/保存到数据库的加载/保存方法。 现在,如果我以B为例,并采用以下工作流:

  • 从列表中删除1个条目
  • 修改了列表中的1个条目
  • 1个条目添加到_a_列表中
现在,我需要使用类似“b.save()”的东西来更新数据库。
那么,保存更改的最佳方法是什么,即识别添加、删除和更新到_a_列表。

一种策略是使用枚举来表示记录的“状态”。即

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

您将给每个记录一个RecordState(默认为record _NEW/record _UNMODIFIED,视情况而定),当调用Save()时,它将对每个记录执行适当的操作,并将其状态重置为record _UNMODIFIED。删除将在处理时从列表中删除。

我的第一个想法是将所有可能的db操作封装为命令对象(命令模式)。通过这种方式,您可以创建任意数量的命令,直到调用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;
}

记录状态确实是个好主意

我建议:

(a) 应用程序将删除的对象保留在数组中,只有在调用类似ORM的代码进行保存(即插入、更新和删除)时,才会实际删除这些对象

(b) ORM上下文需要在内部维护所有对象的幕后列表,这些对象要么是从磁盘中选择的,要么是在RAM中为每个数据库事务创建的(如果不使用事务,则是连接)。当ORM被要求保存时,这个列表被迭代,并且插入、更新和删除都基于这个列表

在第二种情况下,您通常会发现一个额外的要求,即能够在系统的某些部分将对象与ORM分离/分离,以创建状态的持久快照或对象的修改版本(根据某些高级数据流模型或其他模型),而该对象不能立即存储,因此,需要一个额外的位或枚举状态来反映分离。您可能希望能够将对象与ORM事务重新关联/重新附加,但请注意,此处可能涉及完整性问题,如果需要处理,则必须进行处理,并且处理这些问题的方法通常是特定于应用程序的


请注意,在首次保存之前删除的新创建对象不应生成SQL DELETE,因此,使用未修改、新建、更改、删除的枚举在实践中通常是不够的,您还需要删除新对象,如果您同意我的分离理论,则需要删除新对象。

有点晚,但在我看来,您需要的是。您当前的设计就像一个与UoW配合得很好的模型。

我想分享一下我对如何实现“1对n”关系的看法。 侧“1”是主表,而侧“n”对应从(子)表。我想,我们想从双方的角度来处理这种关系。从slave的角度来看,该关系看起来像一个单一的对象属性,可能具有设置/更改/清除该属性指定的对象引用的能力。从master的角度来看,相同的关系将是类似于集合的属性,为我们提供了迭代/添加/删除该集合中的对象引用的方法。 由于对关系的一方所做的任何更改都必须立即从另一方获得,因此我们有两种选择:

  • 立即将更改传播给关系的所有参与者。在这种情况下,可以使用通用容器类实现上述类似集合的属性,并覆盖变更方法。
  • 引入某种中间的“关系实例”对象,它只拥有一个主对象实例的所有关系信息。在这种情况下,任何一方对属性的每次调用都将从该中间对象获取请求的信息。 在两者之间做出选择涉及到回答几个重要问题:

  • 应该如何创建映射类的实例?我们是否可以创建一个实例而不将其保存在IdentityMap中?如何创建新创建对象的链接结构?
  • 是否可以复制映射类的实例,同时保留彼此之间的一些知识,以传播更改?或者每个表记录应该只有一个实例?
  • 在所有可能的情况下,谁负责对象删除? 在这两种情况下,都有一些特性,这些特性通常出现在任何类似ORM的解决方案中。 例如,IdentityMap设计模式假设您注册了映射类的所有实例,这些实例应该在某种注册表中将它们的更改呈现给th DB。这对于以后执行“冲洗”操作是必要的。当然,这需要维护记录状态。 我发现“关系实例”方法相对更容易实现。您可以在我的尚在开发中的C++通用ORM解决方案中找到实现:。特别是,看看源文件DataObject.h、DataObject.cpp和TestDataObject.cpp(文件夹lib/orm/)中的测试。 与示例代码不同,YB.ORM库在内部使用带有静态类型“瘦”包装的变量类型对象。
    DataObject
    类表示映射类的实例,其中映射规则在元数据描述中给出。这样的对象总是在堆中分配,而不是c