C ++ 11中的轻量级数据映射器

时间:2016-03-16 19:34:48

标签: c++ c++11 datamapper

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

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

我的对象派生自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<some class derived from myDataObject>。我的数据库层返回一个结果集,该结果集允许一次检索一行。

如何编写引用对象列表(std:vector<some class derived from myDataObject>&)的数据映射器以及对结果集的引用并填充列表?

其他信息:

目前,我在从myDataObject派生的每个类中重写了2个方法:

  • FromData(myResultSet&amp; resultset):从结果集中的当前行填充'this'对象。
  • SetByName(字符串名称,变量值):根据字符串化名称设置属性。由FromData用于根据结果集中的字段名称设置属性。

我不喜欢这件事,但主要是:

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

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

编辑重新。 rumburak的评论:一旦我解决了阅读问题,我的计划是以某种方式反过来持久化数据。

2 个答案:

答案 0 :(得分:0)

由于您要求从数据库中读取数据,并且似乎对编写没有任何疑问:您是否可以执行与保存数据库中的数据相反的任何操作?

如果不是:

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

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

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

答案 1 :(得分:0)

感谢@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;
}

现在&#39;数据感知&#39;对象可以从中间的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&amp;)。

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

myDerivedDataObject temp(results->GetRow());

&#39;数据映射&#39;部分包括确保结果集列具有正确映射到数据对象成员的名称。