Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: отображение лога из базы данных в таблице на экране  (Прочитано 16697 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« : 25-03-2010 04:52 » 

Казалось бы, простая задача

но, как показывает реальность - нифигааа )))

Имеется таблица LOG с полями

ID  (инкрементный счётчик, индекс),
time  (время рождения сообщения, не путать со временем попадания в базу данных! Это разное)
mess (само сообщение, содержимое - неважно, какое)

Итак, где-то формируются сообщения, хранится время создания сообщений. Затем пачка сообщений приходит на сервер, где сообщения сохраняются в базу (в общем случае - в произвольном порядке).
---------------------------
Рабочее место (клиент) закачивает себе сообщения с сервера, указывая минимальное значение ID, которое он (клиент) уже скачивал.

---------------------
Теперь нам всё нужно отобраззить в таблице на экране клиента. Допустим, сначала хотим отображать в порядке возрастания ID - тут всё предельно просто и красиво: храним "координаты" в программе в переменных
Код:
__int64 m_n64GridTopID____nm1;//id, который сейчас отображается вверху таблицы на экране. Если "==-1" - не валиден(делать всё время наверху)

__int64 m_n64GridCursorID_nm1;//id, на котором установлен курсор в таблице на экране. Если "==-1" - не валиден(делать всё время наверху)

//некий кеш для уменьшения количества обращений к базе
typedef std::map<__int64, message_body> td_LOG;
td_LOG m_LOG;

меняем "координаты", соответственно подгружаем недостающие сообщения из базы в кеш, радуемся.

---------------------
Затем задача такая: Показывать в таблице сортировкой по времени

Как с наиболее меньшими метаниями это реализовать?

Мысли у меня следующие:

1) самое простое в плане дальнейшей работы, но самое сложное в плане сохранения в базу - при сохранении в базу как-то вставлять сообщения так, чтобы если отсортировать по ID, то время тоже будет отсортировано всегда правильно (как это сделать, пока ещё не думал). Тут ещё проблема с синхронизацией с данными на клиенттах - ведь ID будут уже разные для одного и того же сообщения
2) другой вариант - оставить "бардак" со временем в базе, но индексировать время тоже. Но тут очередная проблема - время может повторяться. В итоге нелья применить "координаты", тип которых - время
3) оставляем всё как при сортировке по ID. "Координаты" - имеют тип времени. Перед выводом на экран создаём дополнительный массив (multimap), отсортированный по времени (но в message_body также храним и ID) и выводим в таблицу (тут надо ещё продумать взаимодействие двух массивов)

Какой вариант лучше или, может, вообще как-то по другому надо сделать ?
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #1 : 25-03-2010 05:49 » 

написал ответ, но стёр Улыбаюсь ибо твой пост слишком сумбурен, что бы взять и ответить, вот так сразу

и так имеем:
Код:
table log{
    number id;
    datetime date;
    varchar2[2000] msg;
};

задача:
реализовать инкрементальную загрузку логов на клиенте

Теперь пожалуйста детализируй задачу.

я полагаю, что-то вроде такого:
1. инициировать процесс выгрузки начиная с какой-то даты
2. инициировать процесс выгрузки начиная с конкретного ID

с пунктом 2 всё понятно, с пунктом 1 не очень, посмотрим на опыт зарубежных коллег.
И так, всеми любимый SVN делает следующим образом:
1. я лучше кодом Улыбаюсь select min(id) from log where date>=InterestingDate
2. Так мы получили ID и свели проблему номер 1 к номеру 2
можно возразить, что могут появляться новые ID, но с меньшей датой, это да, но добавление небольшого условия в селект решит проблему. Наверняка всплывут еще шероховатости, но не думаю, что слишком тяжелые в шлифовке.
Записан

Странно всё это....
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #2 : 25-03-2010 06:26 » 

Вроде старался поподробнее описать проблему ))
Ладно, тогда напишу так:

Как всё это выглядит в целом и работает как одна система:

имеется:
Прибор (железка),
Сервер (1-й комп),
Клиент(ы) (2-й комп,(3-й, 4-й, ...))

Клиенты не работают с базой напрямую, а только через Сервер.
Клиенты имеют свои базы, куда заливают сообщения с Сервера для локальной работы с сообщениями.

Прибор генерирует сообщения, ставит штамп времени на них и сразу же отправляет на сервер. Но, если Сервер не прислал подтверждения о приёме сообщения,  то Прибор откладывает сообщение на потом.
После появления в сети Сервера Прибор сразу не отдаёт накопленное, но новые сообщения шлёт сразу, как обычно. Оффлайновые сообщения Сервер забирает с Прибора по некой команде - сразу пачкой.
(В итоге: в общем случае штамп времени у сообщений в базе отсортирован вовсе не в таком же порядке, как ID.)


Далее, Клиент подключается к Серверу и по последнему скаченному ID забирает с него новые сообщения.
(Сейчас ID в базе Клиента и в базе Сервера идентификаторы сообщений ID строго синхронизированы! Это следует из всего вышесказанного)

Теперь, как  сделано сейчас: в таблице на экране отображаются сообщения в порядке убывания ID - то есть вверху таблицы видим самое свежее сообщение. Это несложно сделать - я описал в посте выше, как это организовать по логике. Прокрутка таблицы - просто логическое смещение "указателя" на верхнее видимое сообщение (сейчас - по ID, но надо будет по времени)

Но по штампу времени в общем случае сообщения на экране могут быть перепутаны. Вот тут я застрял... Времени на долгие эксперименты нету, хочется узнать, как это обычно делается, причём желательно переписать только действия Клиента, не трогая Прибор и Сервер
(то есть Клиент по прежнему закачивает себе с Сервера свежие сообщения по ID)
« Последнее редактирование: 25-03-2010 06:29 от Алексей1153++ » Записан

PooH
Глобальный модератор

ru
Offline Offline
Пол: Мужской
... и можно без хлеба!


« Ответ #3 : 25-03-2010 06:36 » 

На клиента выгружаешь по ID, то есть у тебя на клиенте есть все данные, что и в Базе. Теперь на Клиенте ты можешь с этими данными делать что угодно, и как угодно сортировать. Отображение этих данных совсем другая задача. То есть у тебя фактически две задачи, получить на клиенте все данные с БД и отобразить данные, вот и решай их отдельно.
Записан

Удачного всем кодинга! -=x[PooH]x=-
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #4 : 25-03-2010 06:42 » 

PooH, так и решаю задачу - именно отобразить в таблице на экране с возможностью навигации по таблице (прокрутка, фильтр - например, не показывать сообщения некоторых типов). Вывод с сортировкой по ID я решил - это довольно просто оказалось. А вот с сортировкой по времени - затык. Ещё учитывай, что время может повторяться Улыбаюсь
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #5 : 25-03-2010 06:43 » 

Алексей1153++, как это обычно делается я написал Улыбаюсь
теперь как это хранить на клиенте, ну точнее как бы сделал я.

Код:
struct LogRecord
{
   long id_;
   date date_;
   std::sting msg_;
   bool operator<(const LogRecord & rhs)   { return id_ < rhs.id_; }
   static bool LessForSortByDate(const LogRecord & lhs, const LogRecord & rhs)
   {
       if (lhs.date_ != rhs.date_) return lhs.date_ < rhs.date_;
       return lhs < rhs;
   }
};

// контейнер отсортированный по дате
std::multiset<LogRecord, LogRecord::LessForSortByDate> cont;
Записан

Странно всё это....
PooH
Глобальный модератор

ru
Offline Offline
Пол: Мужской
... и можно без хлеба!


« Ответ #6 : 25-03-2010 06:46 » 

Алексей1153++, не пойму в чем проблема, при каждом получении данных пересортировывай и обновляй, иначе никак.
Записан

Удачного всем кодинга! -=x[PooH]x=-
baldr
Команда клуба

cy
Offline Offline
Пол: Мужской
Дорогие россияне


WWW
« Ответ #7 : 25-03-2010 06:58 » 

Алексей1153++, ты же для отображения выбираешь из базы - ну вот в запросе и ставь "order by date".. И фильтрацию и тп - тоже в запросе..
Записан

Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #8 : 25-03-2010 07:03 » 

LogRus, а чем multiset отличается от multimap ? Из описания как-то одно и то же выходит.

The Standard Template Library multiset class is used for the storage and retrieval of data from a collection in which the values of the elements contained need not be unique and in which they serve as the key values according to which the data is automatically ordered. The key value of an element in a multiset may not be changed directly. Instead, old values must be deleted and elements with new values inserted.

The Standard Template Library multimap class is used for the storage and retrieval of data from a collection in which the each element is a pair that has both a data value and a sort key. The value of the key does not need to be unique and is used to order the data automatically. The value of an element in a multimap, but not its associated key value, may be changed directly. Instead, key values associated with old elements must be deleted and new key values associated with new elements inserted.

Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 25-03-2010 07:05 » 

baldr, про запрос тут всё понятно Улыбаюсь Вопрос не в том
PooH, наверное, только так
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #10 : 25-03-2010 07:06 » 

не совсем Улыбаюсь
мапа, хранит пару ключ + элемент и сортирует по ключу
а сет хранит элемент и сортирует через оператор < или через функтор (наш случай)
дополнительно можно навесить индексы если хочется еще сортировок разных поиспользовать
Записан

Странно всё это....
PooH
Глобальный модератор

ru
Offline Offline
Пол: Мужской
... и можно без хлеба!


« Ответ #11 : 25-03-2010 10:05 » 

Алексей1153++, можно каждый раз к базе обращаться.
Записан

Удачного всем кодинга! -=x[PooH]x=-
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 25-03-2010 10:13 » 

можно, но я буду с кешем делать, а то хрустеть винт будет постоянно )
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #13 : 25-03-2010 10:25 » 

и вот ещё одна непонятность.

Пользователь хочет прокрутить таблицу на экране на N строк.  В случае с ID всё было просто - они уникальные. А время то может повторяться - за что тут зацепиться ?
Записан

PooH
Глобальный модератор

ru
Offline Offline
Пол: Мужской
... и можно без хлеба!


« Ответ #14 : 25-03-2010 11:04 » 

Пронумеруй строки.
Записан

Удачного всем кодинга! -=x[PooH]x=-
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #15 : 25-03-2010 11:18 » 

LogRus, а вот так - будет ли одно и то же, что и твой код ?

Код:
struct LogRusRecord
{
   long id_;
   date date_;
   std::sting msg_;

   static bool LessForSortByDate(const LogRecord & lhs, const LogRecord & rhs)
   {
if(lhs.date_ == rhs.date_)
{
return lhs.id_<rhs.id_;
}
else
{
return lhs.date_<rhs.date_;
}
   }
};

// контейнер отсортированный по дате
std::multiset<LogRusRecord, LogRusRecord::LessForSortByDate> cont;

PooH, то есть , надо добавить ещё не связанный с базой инкрементный счётчик, так понимаю
Записан

PooH
Глобальный модератор

ru
Offline Offline
Пол: Мужской
... и можно без хлеба!


« Ответ #16 : 25-03-2010 11:19 » 

Ну я так понимаю, ты можешь в клиенте после сортировки пронумеровать строки (если они контролом не нумеруются) ну и двигать потом куда хочешь.
Записан

Удачного всем кодинга! -=x[PooH]x=-
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #17 : 25-03-2010 12:10 » 

А вот мысль заработала Улыбаюсь Всё гораздо проще - надо сделать составной индекс (соотвественно переписав всё, что потянется)

то есть, вместо

Код:
struct LogRusRecord
{
long id_;
date date_;
...
...
};

сделать

Код:

struct s_DateIdIndex
{
date date_;
long id_;
};


struct s_LogRusRecord
{
s_TimeIdIndex DII;
...
...
};

тогда, даже если время одинаковое, разницу можно ощутить по id_, то есть DII - уникален Улыбаюсь

Ещё не попробовал, но чисто интуитивно - переписать всё по аналогии со случаем, когда сортировали по ID



-----------
А ещё вопросик - поиск в set/multiset выполняется медленнее, чем в map/multimap ?
« Последнее редактирование: 25-03-2010 12:12 от Алексей1153++ » Записан

PooH
Глобальный модератор

ru
Offline Offline
Пол: Мужской
... и можно без хлеба!


« Ответ #18 : 25-03-2010 14:17 » 

у тебя ID всегда по порядку появляются, а время может появляться в произвольном и попробуй потом в этом индексе разберись =) Можно конечно для определенности принять, что при одинаковом времени сортировка идет по id, но это ли надо?
« Последнее редактирование: 25-03-2010 14:21 от PooH » Записан

Удачного всем кодинга! -=x[PooH]x=-
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #19 : 25-03-2010 16:17 » 

самое главное, что теперь есть действительно уникальный индекс ) Что многое упрощает. А сортировка - всегда только по времени, по ID не нужно
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #20 : 26-03-2010 04:06 » 

тогда, даже если время одинаковое, разницу можно ощутить по id_, то есть DII - уникален Улыбаюсь
вообще, оно так и работало Улыбаюсь в моём коде
LogRus, а вот так - будет ли одно и то же, что и твой код ?

Код:
struct LogRusRecord
{
   long id_;
   date date_;
   std::sting msg_;

   static bool LessForSortByDate(const LogRecord & lhs, const LogRecord & rhs)
   {
if(lhs.date_ == rhs.date_)
{
return lhs.id_<rhs.id_;
}
else
{
return lhs.date_<rhs.date_;
}
   }
};


блок else убери только, сразу делай return, а то не красиво.

А ещё вопросик - поиск в set/multiset выполняется медленнее, чем в map/multimap ?

это одно и тоже Улыбаюсь представляешь, т.е. если ты откроешь код и посмотришь, что к чему, то увидишь, что это один шаблон с разными traits (хранить элемент или пару, поддерживать уникальность или нет)
Записан

Странно всё это....
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #21 : 26-03-2010 04:21 » 

else не уберу - мне так красиво как раз )

А в остальном - понятно, пасиба
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #22 : 26-03-2010 04:23 » new

Алексей1153++, вообще если у тебя нет оператора < (если он тебе не нужен), то можешь
static bool LessForSortByDate(const LogRecord & lhs, const LogRecord & rhs)
заменить на operator <
тогда не надо LessForSortByDate передавать, как параметр шаблона
Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines