Russian Qt Forum
Май 10, 2024, 23:00 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4 5   Вниз
  Печать  
Автор Тема: Вопрос сохранения данных.  (Прочитано 30977 раз)
alexis031182
Гость
« Ответ #30 : Июнь 27, 2012, 12:09 »

У меня задача вроде бы и простая, но чето никак. суть в том что у меня есть окошко с QTreeView+QStandardItemModel. Дерево состоит из двух уровней. Первый уровень - это данные из одной таблицы. Второй уровень - данные из другой таблицы. Между этими табличками связь "многие-ко-многим".
Для организации связи "многие-ко-многим" у Вас должна быть ещё одна таблица ссылок в БД.

То есть если я добавляю дочерний узел, то эта запись должна пойти в базу и прицепиться к родительскому узлу.
В этом случае в БД, в две таблицы нужно добавить по одной записи: одна запись, собственно, дочерний узел, а вторая запись - идентификатор этого узла, плюс идентификатор родительского узла в таблице ссылок.

Для наглядности картинку с окошком прицепила. Вот если я убираю дочерние узлы, то реализуется все на раз-два. А сними начинается куча проблем. Дочерние узля кстати можно создавать и в окошке и выбирать ранее созданные из базы этих объектов (по тз было перетаскиванием, короче там ещё dragand drop замешан))), вот.
Опишите более детально проблемы.
Записан
nata267
Гость
« Ответ #31 : Июнь 27, 2012, 12:10 »

И еще когда рисую диаграммы, получается быстрее. Как только пишу код, начинаю вязнуть в проблемах интерфейса пользователя и не могу наглядно представить как все это работает. Это к тому что сначала нужно думать а потом делать).
Записан
nata267
Гость
« Ответ #32 : Июнь 27, 2012, 12:11 »

У меня задача вроде бы и простая, но чето никак. суть в том что у меня есть окошко с QTreeView+QStandardItemModel. Дерево состоит из двух уровней. Первый уровень - это данные из одной таблицы. Второй уровень - данные из другой таблицы. Между этими табличками связь "многие-ко-многим".
Для организации связи "многие-ко-многим" у Вас должна быть ещё одна таблица ссылок в БД.

То есть если я добавляю дочерний узел, то эта запись должна пойти в базу и прицепиться к родительскому узлу.
В этом случае в БД, в две таблицы нужно добавить по одной записи: одна запись, собственно, дочерний узел, а вторая запись - идентификатор этого узла, плюс идентификатор родительского узла в таблице ссылок.

Для наглядности картинку с окошком прицепила. Вот если я убираю дочерние узлы, то реализуется все на раз-два. А сними начинается куча проблем. Дочерние узля кстати можно создавать и в окошке и выбирать ранее созданные из базы этих объектов (по тз было перетаскиванием, короче там ещё dragand drop замешан))), вот.
Опишите более детально проблемы.

естесственно это все есть. то что на картинке это уже выборка из бд. проблеммы опишу попозже. их куча и диаграммы классов которые есть скину)) да и вообще программа уже написана, правда там не все работает, хотелось улучшить и дописать нереализованный функционал)
« Последнее редактирование: Июнь 27, 2012, 12:13 от nata267 » Записан
nata267
Гость
« Ответ #33 : Июнь 27, 2012, 12:34 »

Проблема №1:
Есть связываемые объекты это TestBlock и Task. Т.е. тестовые блоки и задания, которые к ним прицеплены.
Есть метод формы, в котором идет загрузка объектов из бд и добавление их в модель вьюхи.

Код:
void TestBlockEditor::setCourse(int courseId)
{
     m_courseId = courseId;
     m_testBlockView->model()->clearTestBlocks();

    // m_actionEdit->setEnabled(false);
    // m_actionCopy->setEnabled(false);
    // m_actionCut->setEnabled(false);
     m_actionDelete->setEnabled(false);

     TestBlockList testBlockList = TestBlock::load(courseId);
     foreach (TestBlock *tb, testBlockList) {
            m_testBlockView->model()->addTestBlock(tb);
            //connect(tb, SIGNAL(changed()), this, SLOT(slotTestBlockChanged()));
     }
}

Вот метод load объекта TestBlock, который возвращает список объектов TestBlock, для открытого проекта.
Код:
QList<TestBlock*> TestBlock::load(int courseId)
{
    QList<TestBlock*> list;

    QSqlQuery query;
    query.exec(QObject::tr("SELECT id FROM test_blocks WHERE course_id=%2").arg(courseId));
    while(query.next()) {
           int id = query.value(0).toInt();
           TestBlock *testBlock = new TestBlock(id);
           list.append(testBlock);
    }

    return list;
 }

Это только в случае без связей. Как добавить связи. Те объект TestBlock должен содержать указатели на объекты Task??
Как это реализовать не через одно место?? Загрузку и привязку объектов. До того как передавать их в модель вьюхи?
Записан
alexis031182
Гость
« Ответ #34 : Июнь 27, 2012, 12:47 »

Встречный вопрос: зачем Вам нужно жёстко указывать связи между объектами, если модель сама по себе и предназначена для организации связей между объектами?
Записан
nata267
Гость
« Ответ #35 : Июнь 27, 2012, 13:16 »

Встречный вопрос: зачем Вам нужно жёстко указывать связи между объектами, если модель сама по себе и предназначена для организации связей между объектами?

А как мне понять какие задания привязаны к каким тестовым блокам? Я думала хранить указатели на них. Т.е. допустим выбрать сначала все объекты одного типа для данного проекта, затем все объекты другого типа для данного проекта. Потом в объектах типа "тестовый блок" создать список указателей на объекты типа "задание". и тогда в QStandardItemModel генерировать дерево. и тогда у меня будут 2 глобальных списка объектов этих типов и для каждого объекта я думала поставить статусы, по которым будут производится обновление в базе данных(удаление обновление вставка). но это через одно место, а как вообще надо делать хз.
Записан
nata267
Гость
« Ответ #36 : Июнь 27, 2012, 13:17 »

Встречный вопрос: зачем Вам нужно жёстко указывать связи между объектами, если модель сама по себе и предназначена для организации связей между объектами?

а вообще не очень поняла смысл вопроса?
Записан
alexis031182
Гость
« Ответ #37 : Июнь 27, 2012, 13:45 »

А как мне понять какие задания привязаны к каким тестовым блокам?
Вот Вы получаете список тестовых блоков в функции TestBlock::load(). В макросе foreach, в этой функции Вы каждый тестовый блок добавляете сразу в модель. А почему бы не сделать здесь запрос к БД и получить список заданий, относящихся к этому тестовому блоку. И когда Вы добавите в модель текущий тестовый блок, тут же добавляйте в модель тестовые задания этого блока, и естественно с указанием родительского отношения.

Я думала хранить указатели на них. Т.е. допустим выбрать сначала все объекты одного типа для данного проекта, затем все объекты другого типа для данного проекта. Потом в объектах типа "тестовый блок" создать список указателей на объекты типа "задание". и тогда в QStandardItemModel генерировать дерево. и тогда у меня будут 2 глобальных списка объектов этих типов...
Зачем, если имеется модель, строить параллельную иерархию на указателях? Это на мой взгляд избыточно.

и для каждого объекта я думала поставить статусы, по которым будут производится обновление в базе данных(удаление обновление вставка). но это через одно место, а как вообще надо делать хз.
Ну сохранение факта того, что объект изменился действительно необходимо для того же отката изменений или для избежания избыточности при сохранении не изменившихся данных. Вопрос лишь в том, как лучше сделать. Здесь можно посмотреть в сторону паттернов, но если у Вас объекты используют сигнал/слоты, то неприятностей избежать не удастся.
Записан
nata267
Гость
« Ответ #38 : Июнь 27, 2012, 13:59 »

А как мне понять какие задания привязаны к каким тестовым блокам?
Вот Вы получаете список тестовых блоков в функции TestBlock::load(). В макросе foreach, в этой функции Вы каждый тестовый блок добавляете сразу в модель. А почему бы не сделать здесь запрос к БД и получить список заданий, относящихся к этому тестовому блоку. И когда Вы добавите в модель текущий тестовый блок, тут же добавляйте в модель тестовые задания этого блока, и естественно с указанием родительского отношения.


Те вы хотите сказать что надо написать чтото типа:
Код:
     TestBlockList testBlockList = TestBlock::load(courseId);
     TaskList taskList;
     foreach (TestBlock *tb, testBlockList) {
            m_testBlockView->model()->addTestBlock(tb);
            //connect(tb, SIGNAL(changed()), this, SLOT(slotTestBlockChanged()));
           
            taskList.clear();
            taskList = Task::load(tb->id());
            foreach(Task task, taskList)
            {
                    m_testBlockView->model()->addTaskToTestBlock(task, tb);
                    //connect(task, SIGNAL(changed()), this, SLOT(slotTaskChanged()));
             }
     }

Непонимающий
Записан
nata267
Гость
« Ответ #39 : Июнь 27, 2012, 14:02 »

Да круто. И тогда все изменения будут храниться в модели, а при сохранении вносится в базу. Не сообразила сама, спасибо
Записан
alexis031182
Гость
« Ответ #40 : Июнь 27, 2012, 14:04 »

Те вы хотите сказать что надо написать чтото типа:
...
Да, именно так.
Записан
nata267
Гость
« Ответ #41 : Июнь 28, 2012, 15:53 »

Теперь сделала так. Все связи хранятся в модели QStandardItemModel. При удалении объектов (до сохранения) указатели на объекты и связи хранятся в командах, из модели удаляются. При отмене удаления снова добавляются в модель.

Это слот по кнопке удалить:

Код:
void TestBlockEditor::slotDelete()
{
    DbObject *selection = m_testBlockView->selectedDbObject();
    if (!selection)
        return;

    if(TestBlock *tb = dynamic_cast<TestBlock *>(selection)) {

        RemoveTestBlockCommand::TaskData taskData = m_testBlockView->model()->tasksOfTestBlock(tb);
       
        RemoveTestBlockCommand *cmd = new RemoveTestBlockCommand(this);
        cmd->init(tb, taskData);
        m_commandHistory->push(cmd);
    }

    if(Task *task = dynamic_cast<Task *>(selection)) {

        TestBlock *tb = m_testBlockView->model()->testBlockOfTask(task);
        if(!tb)
            return;
       
        RemoveTaskCommand *cmd = new RemoveTaskCommand(this);
        cmd->init(task, tb);
        m_commandHistory->push(cmd);
    }
}

Не нравятся dynamic_cast. Как от них избавится??

Это команда, удаляющая тестовый блок:

Код:
RemoveTestBlockCommand::RemoveTestBlockCommand(TestBlockEditor *editor):
      QUndoCommand(QObject::tr("Удалить тестовый блок")),
      m_editor(editor),
      m_testBlock(0)
{
}

void RemoveTestBlockCommand::init(TestBlock *tb, const TaskData &taskData)
{
    Q_ASSERT(m_testBlock == 0);
    m_testBlock = tb;
    m_taskData = taskData;
}

void RemoveTestBlockCommand::redo()
{
    m_editor->unmanageTestBlock(m_testBlock);
}

void RemoveTestBlockCommand::undo()
{
    m_editor->manageTestBlock(m_testBlock, m_taskData);
}

И методы manageTestBlock, unmanageTestBlock окошка, которые удаляют-добавляют элемент в модель

Код:
void TestBlockEditor::manageTestBlock(TestBlock *tb, const QList<Task*> &dataTask)
{
    QModelIndex index = m_testBlockView->model()->addTestBlock(tb);
    m_testBlockView->setExpanded(index, true);
    m_testBlockView->setCurrentIndex(index);
    //connect(tb, SIGNAL(changed()), this, SLOT(slotTestBlockChanged()));

    foreach(Task *task, dataTask)
    {
        m_testBlockView->model()->addTaskToTestBlock(task, tb);
        //connect(task, SIGNAL(changed()), this, SLOT(slotTaskChanged()));
    }
}

void TestBlockEditor::unmanageTestBlock(TestBlock *tb)
{
    //disconnect(tb, SIGNAL(changed()), this, SLOT(slotTestBlockChanged()));

    const QModelIndex idx = m_testBlockView->model()->findObject(tb);
    if (idx.isValid())
        m_testBlockView->model()->removeRow(idx.row());
}

То есть отмена действий работает. Теперь проблемы с общим сохранением( Если делать обход модели, то удаленных элементов в ней нет. НО для них можно вести отдельный список. Задание в этой форме не должны удаляться а только связи с тестовыми блоками. Получается нужно хранить ещё и список этих удаленных связей? А при добавлении задания (которые могут быть как новыми так и существующими), нужно добавлять не только связь но и заданиие если оно новое. Получается очень запутанно.  
« Последнее редактирование: Июнь 28, 2012, 16:00 от nata267 » Записан
DmitryM
Гость
« Ответ #42 : Июнь 28, 2012, 22:52 »

Для организации дерева использовал бы паттерн компоновщик, т.к. использовал бы иерархию объектов.
Для откатов петтерн хранитель, и путь этим занимаются сами объекты в узлах/листьях дерева.
Сохранение всего этого дела, сделал бы через сериализацию в xml.
Записан
nata267
Гость
« Ответ #43 : Июнь 29, 2012, 08:50 »

Для организации дерева использовал бы паттерн компоновщик, т.к. использовал бы иерархию объектов.
Для откатов петтерн хранитель, и путь этим занимаются сами объекты в узлах/листьях дерева.
Сохранение всего этого дела, сделал бы через сериализацию в xml.


как понять через сериализацию в xml. у меня бд mysql
Записан
DmitryM
Гость
« Ответ #44 : Июнь 29, 2012, 11:07 »

Хранение деревьев в реляционных базах данных нетривиальная немного не тривиальная задача.
Одно из возможных решений использовать ORM(Object-relational mapping).
Записан
Страниц: 1 2 [3] 4 5   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.061 секунд. Запросов: 20.