Очень хочется засунуть работу с СУБД в отдельный класс, чтобы основная
работа программы шла только с объектами типа
class Person
{
property<int> id;
property<std::string> name;
...
};
и не зависела от запросов, таблиц...
Но тут возникает проблема — как обозначить соответствие между именами
полей в таблице БД и членами класса.
Хочется, чтобы работало примерно следующим образом:
Person p;
property<int>& id = binder<p,"PersonID">;
property<std::string>& name = binder<p,"PersonName">;
То есть по экземпляру класса и строке нужно возвращать ссылку на член
этого класса.
И обратно:
std::string field_name = binder<p,p.id>
То есть по экземпляру класса и ссылке(?) на член возвращать стоку с
названием поля.
Пока я придумал делать только так:
---------------------------------------------------------------
template<class T>
class bounder
{
public:
prop_base& operator()(const std::string& fname, T& obj)
{
}
};
void f()
{
property<int>& id = b_cast<int>(p, "PersonID");
}
---------------------------------------------------------------
А как сделать наоборот(получить строку по члену класса) придумать не
могу. Единственное, что приходит на ум — использовать offsetof, но это
как-то неправильно с точки зрения ОП...
Может кто сталкивался с такими проблемами? Подскажите как быть...
Может я вообще не то делаю?
Здравствуйте, Yagg, Вы писали:
Y>Очень хочется засунуть работу с СУБД в отдельный класс, чтобы основная Y>работа программы шла только с объектами типа Y>class Person Y>{ Y> property<int> id; Y> property<std::string> name; Y> ... Y>};
Должна быть фабрика, которая будет общаться с БД и читать/записывать memento и создавать твои конкретные классы. Так как класс обращается к свом свойствам по символьным именам, запросы к БД должны при необходимости переименовывать столбцы.
Св-ва для удобства можно обернуть в proxy, которые различают запись и чтение.
Y>и не зависела от запросов, таблиц...
Вот чтобы она ни отчего не зависела сделать непросто.
Re[2]: binder
От:
Аноним
Дата:
15.09.03 12:08
Оценка:
Здравствуйте, MaximE, Вы писали:
ME>Здравствуйте, Yagg, Вы писали:
Y>>Очень хочется засунуть работу с СУБД в отдельный класс, чтобы основная Y>>работа программы шла только с объектами типа Y>>class Person Y>>{ Y>> property<int> id; Y>> property<std::string> name; Y>> ... Y>>};
ME>Например так (memento pattern):
ME>
Поясни, плиз, из какой библиотеки variant_cast ?
(я так понимаю она из _variant_t в соответствующий тип преобразует ) ...
ME>Должна быть фабрика, которая будет общаться с БД и читать/записывать memento и создавать твои конкретные классы. Так как класс обращается к свом свойствам по символьным именам, запросы к БД должны при необходимости переименовывать столбцы.
ME>Св-ва для удобства можно обернуть в proxy, которые различают запись и чтение.
Y>>и не зависела от запросов, таблиц...
ME>Вот чтобы она ни отчего не зависела сделать непросто.
Здравствуйте, MaximE, Вы писали:
ME>Например так (memento pattern):
[...] ME>private: ME> typedef map<string, variant> memento; ME> memento memento_;
Очень смущает присутствие лишних данных. Объектов ведь будет много и все в памяти,
так что держать в _каждом_ объекте описание его полей мне кажется нерациональным.
Делать статическими? Или для каждого класса фабрику?
Здравствуйте, Аноним, Вы писали:
А>Поясни, плиз, из какой библиотеки variant_cast ? А>(я так понимаю она из _variant_t в соответствующий тип преобразует ) ...
Это не важно...
Здравствуйте, Yagg, Вы писали:
Y>Здравствуйте, MaximE, Вы писали:
ME>>Например так (memento pattern): Y>[...] ME>>private: ME>> typedef map<string, variant> memento; ME>> memento memento_; Y>Очень смущает присутствие лишних данных. Объектов ведь будет много и все в памяти, Y>так что держать в _каждом_ объекте описание его полей мне кажется нерациональным. Y>Делать статическими? Или для каждого класса фабрику?
Делать для каждого класса фабрику очень расточительно и утомительно. Фабрика должна быть максимально абстрактной и знать лишь имена запросов к БД для того, чтобы писать/читать мементо и адрес функции для создания класса.
Каждый объект будет содержать только имена и значения своих полей (в memento_). Конечно, можно сэкономить на именах, запихнув значения в vector<> и доступаюсь по индексу. Но так ты сильно потеряешь в гибкости и легкости поддержки.
Я тут тебе привел псевдокод (по поводу varaint_cast<>). Здесь varaint — это может быть и _variant_t и любой другой подходящий tagged/discriminated union (как и было в реальном проекте).
A>Небольшое пояснение для тех, кто не любит ходить по ссылкам. A>Код в примере пишет дамп объекта в XML, используя описание класса:
A>
A> class_("Driver").derived_from<Person>()
A> [
A> member(&Driver::licence_id, "licence_id"), // note comma operator
A> member(&Driver::licence_issue_date, "licence_issue_date")
A> ];
A>
Хм ... вообще-то надо бы еще где нибудь и типы членов классов указывать, а также их длины ( особенно актуально если член класса это char* )
Здравствуйте, Аноним, Вы писали:
A>>Небольшое пояснение для тех, кто не любит ходить по ссылкам. A>>Код в примере пишет дамп объекта в XML, используя описание класса:
A>>
Здравствуйте, Аноним, Вы писали: А>Хм ... вообще-то надо бы еще где нибудь и типы членов классов указывать, а также их длины ( особенно актуально если член класса это char* )
если тип char[N] то размер выводится, правда остается открытым вопрос насчет нуля в конце. char* логично, что это указатель на один char. Даже если я сделаю метод array, который принимает массив на пару с длиной, то непонятно, кто и как этот массив удаляет.
Поясню примером:
struct Person
{
char first_name[80];
char* last_name;
size_t last_name_len;
~Person()
{
// удалять или нет last_name?
}
};
class_("Person")
[
member(&Person::first_name, "first_name"), // длину массива можно узнать
array(&Person::last_name, &Person::last_name_len, "last_name")
];
Лучше использовать типы с общеизвестной стратегией удаления элементов. std::string или std::vector<char> вместо char*, а auto_ptr или shared_ptr для обычных указателей. Если в библиотечку добавить поддержку этих типов, то она правильно сумеет инициализировать объект при загрузке, а программист не будет думать об удалении в деструкторе.