jeudi 25 avril 2019

How to dynamically set object's property based on prop name?

I hope it will be clear what I want to do.

I want to fetch data from database based on properties of provided object and then fill those properties with the retrieved data. So, if for example a user defines a class

class Person
{
   public:
      int Id;
      string Name;
};

and then when he calls MyDatabase.Instance.ExecQuery<Person>() it should return Person object filled with information.

What I did is: a user should define the class as following:

class Person : public DBEntity
{
    ENTITIY_PROP(Person , int, Id)
    ENTITIY_PROP(Person , string, Name)
};

The defined macros ensure to add the name and type of the properties to _propsMeta. Now, how do I set object's property based on it's name (see ExecQuery)?

MY INITIAL SOLUTION
I though to add map that maps property to a function that sets the property but I cannot have a map of references to functions with different signatures. Any ideas? If you think I need to change my design to accomplish what I need - let me know.

template <typename T>
void ExecQuery()
{
    static_assert(std::is_base_of<DBEntity, T>(), "a Class should inherit from DBEntity");

    const auto& props = entity->GetPropsMeta();
    auto row = GetData(props);
    T entity = new T();
    for (const auto& colName : row.Columns)
    {
        string val = row[colName];
        // TODO: SET ENTITY'S PROPERTY colName with val
    }
}

#define ENTITIY_PROP(Class, Type, Name) \
        private: \
            int _##Name; \
        public: \
            class Property_##Name { \
            public: \
                Property_##Name(Class* parent) : _parent(parent) \
                { \
                    _parent->SetPropMeta(#Name, #Type); \
                } \
                Type operator = (Type value) \
                { \
                    _parent->Set##Name(value); \
                    return _parent->Get##Name(); \
                } \
                operator Type() const \
                { \
                    return static_cast<const Class*>(_parent)->Get##Name(); \
                } \
                Property_##Name& operator =(const Property_##Name& other) \
                { \
                    operator=(other._parent->Get##Name()); return *this; \
                }; \
                Property_##Name(const Property_##Name& other) = delete; \
            private: \
                Class* _parent; \
            } Name { this }; \
            \
            Type Get##Name() const { return _##Name; } \
            void Set##Name(int value) { _##Name = value; } \

    class DBEntity
    {
    private:
        std::unordered_map<std::string, std::string> _propsMeta;

    public:
        const std::unordered_map<std::string, std::string>& GetPropsMeta() { return _propsMeta; }    
    };

Aucun commentaire:

Enregistrer un commentaire