Тонкости маппинга данных в объекты

radioheaded

PHP нуб
Хочется услышать мнения относительного того, как именно вы предпочитаете маппить данные, требующие некоторого преобразования.

Сразу оговорюсь: представим, что речь идет о легаси коде, который очень тяжело изменить и в котором маппинг по сути выполняется руками, ибо в объектах нет никакой информации о типах полей, а притащить сюда какой-либо ORM вообще без шансов.

Приведу пример и варианты.

В таблице есть поле типа SET (назовем его s), есть логичное желание маппить его в массив, ибо с массивами удобнее работать. Итак, из базы мы получаем строку значений, разделенных запятыми. Есть несколько вариантов работы в этом случае.

1. В объекте храним всегда только массив (преобразованные данные). Тогда при получении данных из базы все такие поля преобразуем в массив, при сохранении объекта обратно собираем строку из массива. Так удобно работать, но приходится прописывать преобразование в методах выборки и изменения данных. Почему — еще раз читаем выше со слом «сразу оговорюсь». Еще, если задуматься о производительности (да-да, экономия на спичках), то здесь мы делаем лишние действия, которые, возможно, не будут востребованы.

2. В объекте храним строку (то есть данные в том виде, в котором они пришли к нам из базы), а в геттерах и сеттерах прописываем логику преобразования. Тогда данные в объекте всегда готовы к вставке/изменению в базе единым способом, никаких дополнительных преобразований уже не требуется. И здесь преобразование выполняется только тогда, когда это действительно нужно. Но зато, если с полем будет выполняться несколько изменений, то будет выполнено несколько лишних преобразований.

3. Ну и все равно найдется кто-то, кто скажет, что можно предварительно готовить схему маппинга с типами и прочими данными, тогда все будет автоматически в обе стороны работать хорошо, поэтому вынесу отдельным вариантом. По сути, это первый универсализированный вариант.

На самом деле, у меня такой проблемы нет, просто захотелось поговорить. Привет ) Так что скажете?
 

fixxxer

К.О.
Партнер клуба
Ну раз сегодня пятница...

Код:
select
   a as `set[a]`,
   b as `int[b]`,
   c as `boolean[c]`, 
from table ...
вычитываем понятно как (parse_str), фабрикой делаем объекты (по классу на тип, конструктор конвертит строку в что надо) с перегруженными __toString, которые возвращают соответствующие куски sql, пригодные для подстановки в insert/update.

:D
 

radioheaded

PHP нуб
Ну раз сегодня пятница...

Код:
select
   a as `set[a]`,
   b as `int[b]`,
   c as `boolean[c]`, 
from table ...
вычитываем понятно как (parse_str), фабрикой делаем объекты (по классу на тип, конструктор конвертит строку в что надо) с перегруженными __toString, которые возвращают соответствующие куски sql, пригодные для подстановки в insert/update.

:D
Оригинально )
 

С.

Продвинутый новичок
Ты забыл про вариант ленивого ручного маппинга.
 

С.

Продвинутый новичок
2. (...) Но зато, если с полем будет выполняться несколько изменений, то будет выполнено несколько лишних преобразований.
Тогда что означает эта фраза?
 

С.

Продвинутый новичок
"Лениво" означает, что ты читаешь данные и оставляешь их в сыром виде. Делаешь преобразование при первом обращении к свойству, запоминаешь их и впредь используешь уже преобразованные данные. В таком случае не будет оверхеда как из п.1, так и из п.2.
 

radioheaded

PHP нуб
"Лениво" означает, что ты читаешь данные и оставляешь их в сыром виде. Делаешь преобразование при первом обращении к свойству, запоминаешь их и впредь используешь уже преобразованные данные. В таком случае не будет оверхеда как из п.1, так и из п.2.
Я говорю в точности об этом же. Но еще раз: лениво можно только получать данные. Давайте лучше пример, а то так, наверное, не совсем понятно.

- Сделали выборку, там поле s='a,b,c', поле s объекта содержит это же сырое значение.
- Понадобились эти данные, дергаем геттер, строка преобразуется в массив [a,b,c], массив сохраняется отдельно и возвращается.
- Изменяем данные, добавляем значение d в массив, получаем в преобразованных данных [a,b,c,d], но в сырых данных по-прежнему 'a,b,c', поэтому надо сделать implode, ибо мы хотим иметь в любой момент данные, готовые к вставке в запрос без дополнительных преобразований. Если же мы изменяем только массив, то при сохранении объекта в базу нам где-то потребуется преобразование в строку, а это уже первый вариант.
 

С.

Продвинутый новичок
- Изменяем данные, добавляем значение d в массив, получаем в преобразованных данных [a,b,c,d], но в сырых данных по-прежнему 'a,b,c', поэтому надо сделать implode, ибо мы хотим иметь в любой момент данные, готовые к вставке в запрос без дополнительных преобразований.
Зачем тебе "иметь в любой момент данные, готовые к вставке в запрос без дополнительных преобразований"? Какой религиозный канон не позволяет это сделать один раз перед вставкой в базу?
 

С.

Продвинутый новичок
Если же мы изменяем только массив, то при сохранении объекта в базу нам где-то потребуется преобразование в строку, а это уже первый вариант.
А понял, ты видишь вариант 1 и вариант 2. Комбинированного варианта (читать по 2, писать по 1) ты не видишь.
 

radioheaded

PHP нуб
Зачем тебе "иметь в любой момент данные, готовые к вставке в запрос без дополнительных преобразований"? Какой религиозный канон не позволяет это сделать один раз перед вставкой в базу?
Началоооось )) Мне это ни к чему, я описал возможные варианты, а в этом суть второго из них. Просто можно суп есть ложкой, можно руками, а можно пить из тарелки. Я пытаюсь узнать, как можно еще и почему так лучше, а так хуже.

Впрочем, могу привести пример оверхеда при первом варианте. Есть таблица, в ней 20 полей и все типа SET. Нам надо обновить значение одного из них обычным способом (ну то есть, понятно, что можно сформировать нужный UPDATE без лишней фигни, но мы сейчас о маппинге). И тогда имеем 20 преобразований в массив, 1 изменение массива, 20 преобразований в строку. Тогда как во втором варианте было бы 1 преобразование туда и обратно.
 

radioheaded

PHP нуб
А понял, ты видишь вариант 1 и вариант 2. Комбинированного варианта (читать по 2, писать по 1) ты не видишь.
Да, вы правы ) Пусть это будет вариант 4. Хотя есть причины, по которым я его не рассматриваю, но не в рамках этой беседы )
 

С.

Продвинутый новичок
"Туда" ты преобразуешь при первом запросе свойства.
"Обратно" ты преобразуешь только те свойства, что было изменены. Делаешь это непосредственно перед записью в базу.
Где оверхед?

P.S. Ты меня начинаешь настораживать.
 

radioheaded

PHP нуб
"Туда" ты преобразуешь при первом запросе свойства.
"Обратно" ты преобразуешь только те свойства, что было изменены. Делаешь это непосредственно перед записью в базу.
Где оверхед?

P.S. Ты меня начинаешь настораживать.
Впрочем, могу привести пример оверхеда при первом варианте.
 

С.

Продвинутый новичок
Пусть это будет вариант 4. Хотя есть причины, по которым я его не рассматриваю, но не в рамках этой беседы )
Странно. Вариант 1 тебя формально устраивает. Вариант 2 -- тоже. Вариант 4, состящий из наиболее оптимальных частей 1 и 2 -- выходит за рамки. Очень странно! Настороженность еще более повысилась.
 

radioheaded

PHP нуб
Давайте так, сначала обновить страницу, потом писать комментарий )
 

radioheaded

PHP нуб
Странно. Вариант 1 тебя формально устраивает. Вариант 2 -- тоже. Вариант 4, состящий из наиболее оптимальных частей 1 и 2 -- выходит за рамки. Очень странно! Настороженность еще более повысилась.
Мне лень вдаваться в подробности, но я попробую донести мысль. Допустим, теперь нам еще надо кешировать эти объекты. Причем, мы как честные программисты хотим кешировать не сами объекты, ибо это некошерно, а только чистые данные. Для этого нам неплохо бы иметь метод, который бы возвращал нам данные, пригодные для кеширования. Причем эти данные должны соответствовать интерфейсу, при помощи которого мы наполняем объект. Хочется, чтобы он на самом деле не отличался от того универсального метода, которым мы возвращаем данные для вставки в базу. Так вот, в варианте 4 нужно будет писать отдельный метод для таких нужд. Вообще это не проблема, не поймите меня неправильно. Мы просто рассматриваем разные варианты с разных сторон )
 

С.

Продвинутый новичок
Ну ни хрена себе! И ты хотел скромно оставить эти требования за рамками дискуссии? Превожу твою хотелку на бытовой язык: и рыбку съесть, и на йух сесть, и чтоб без оверхеда в обоих случаях.

Разговор неконструктивен, Я умываю руки.
 

radioheaded

PHP нуб
Да это не требования, а просто такие хотелки, из которых обычно приходится выбирать что-то одно. Хотя, как вы правильно выразились на бытовом языке, хочется получить идеальный вариант.
 
Сверху