【问题标题】:Lightweight Data Mapper in C++11C++11 中的轻量级数据映射器
【发布时间】:2016-03-16 19:34:47
【问题描述】:

我想在“网格”控件中显示业务层对象列表。我还想在对话框中编辑任何给定的对象。

对象保存在关系数据库中,该数据库还执行引用和多用户完整性。尽管业务对象与数据库表非常相似,但我想在一定程度上使用某种“数据映射器”将它们解耦。

我的对象派生自 myDataObject 基类。基类有一个静态成员如下:

// Initialise a static list of member names for this class. Used when the object is displayed in a grid.
const std::vector<myDataObjectDescriptor> myDataObject::m_Descriptors 
{
    { myDO_INT_FIELD, "UID", "m_UID", 40, false, false },
    { myDO_STRING_FIELD, "TITLE", "m_Title", 200, true, false },
    { myDO_STRING_FIELD, "DESCRIPTION", "m_Description", 400, true, false }
};

此描述符列表允许网格控件直接呈现具有正确列标题和宽度的对象列表。我可以使用 lambda 扩展基类描述符:

// Static initialisation of descriptor list using a lamda.
const std::vector<myDataObjectDescriptor> myDerivedDataObject::m_Descriptors = [] 
{ 
    std::vector<myDataObjectDescriptor> v = myDataObject::m_Descriptors; 
    v.push_back ({myDO_STRING_FIELD, "BACKGROUND", "m_Background", 120, false, false}); 
    v.push_back ({myDO_STRING_FIELD, "FONT", "m_Font", 120, false, false}); 
    return v; 
} ();

到目前为止一切顺利。现在,我想从数据库查询中创建一个对象列表,该列表可以是std::vector&lt;some class derived from myDataObject&gt;。我的数据库层返回一个结果集,允许一次检索一个行。

如何编写一个数据映射器,它接受对对象列表 (std:vector&lt;some class derived from myDataObject&gt;&amp;) 的引用和对结果集的引用并填充列表?

附加信息:

目前我有 2 个方法在从 myDataObject 派生的每个类中被覆盖:

  • FromData (myResultSet& resultset):从结果集中的当前行填充“this”对象。
  • SetByName(字符串名称,变量值):根据其字符串化名称设置属性。 FromData 使用它来根据结果集中的字段名称设置属性。

对此我有很多不喜欢的地方,但主要是:

  • myDataObject 不应该对数据库层有任何了解(也 紧密耦合)。
  • SetByName 是一系列 if 语句,如果 'name' 参数匹配,则设置属性,即

    if (name == "m_Title")
        m_Title = value;
    

编辑重新。 rumburak 的评论:一旦我解决了阅读问题,我计划以某种方式对持久化数据进行相反的处理。

【问题讨论】:

    标签: c++ c++11 datamapper


    【解决方案1】:

    由于您询问的是从数据库中读取数据,并且似乎对写入没有任何疑问:您不能只做与将数据持久化到数据库中的操作相反的事情吗?

    如果没有:

    您可以将结果行转换为将myDataObjectresultRow 解耦的中间对象。该对象可能具有已知字段的已知数据成员和其他字段的一个或多个映射,例如

    struct mySerializedObject
    {
       int id;
       std::string title;
       std::map<std::string, std::string> texts;
       std::map<std::string, int> numbers;
    };
    

    然后数据对象的fromSerialized 函数可以选择他们需要的东西。

    【讨论】:

    • 谢谢!你说得对,我应该提到写作,我的计划是先解决阅读,然后再做相反的写作!您的回答和this question 中的讨论让我走上了一条好路。如果可以的话,我会把我的最终解决方案作为答案。
    【解决方案2】:

    感谢@rumburak 和this answer 的建议,我现在已经解决了我的问题。

    我将结果行转换为通用中间对象,其定义如下:

    typedef std::unordered_map<std::string, boost::any> myDataRow;
    

    然后在我的数据库层中,我有一个 GetRow() 方法,它返回对 myDataRow 的引用。该方法遍历结果集当前记录的列并填充行对象。

    myDataRow& myDataResultSet::GetRow()
    {
        // Get the column names.
        std::vector<myDataColumn>& cols = GetColumns();
    
        // Iterate through the columns, setting the mapped value against the column name.
        // Note: the map's columns are automatically be created on the first use of this function and their contents updated thereafter.
        int i = 0; for (myDataColumn col : cols)
        {
            switch(col.m_Type)
            {
                case dtInteger:
                    m_Data[col.m_Name] = GetInt(i++);
                    break;
    
                case dtString: 
                    m_Data[col.m_Name] = GetString(i++);
                    break;
            }
    
        return m_Data;
    }
    

    现在可以从中间 myDataRow 类初始化“数据感知”对象。

    void myDataObject::FromData(const myDataRow& row)
    {
        auto it = row.find("UID");
        m_UID = it != row.end() ? boost::any_cast<int>(it->second) : 0;
    
        it = row.find("TITLE");
        m_Title = it != row.end() ? boost::any_cast<std::string>(it->second) : "";
    
        it = row.find("DESCRIPTION");
        m_Description = it != row.end() ? boost::any_cast<std::string>(it->second) : ""; : ""; 
    }
    

    每个派生类都调用其父类的 FromData()。它们还有一个方便的构造函数 myDataObject(const myDataRow&)。

    数据映射层现在包括查询数据库和从结果集行填充对象,即:

    myDerivedDataObject temp(results->GetRow());
    

    “数据映射”部分包括确保结果集列的名称正确映射到数据对象的成员。

    【讨论】:

    • 我将把它标记为我的答案,因为这是我最终所做的,但我希望这不会减损@Rumburak 提供的帮助。
    猜你喜欢
    • 2011-11-11
    • 2015-08-21
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多