Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема при удалении директории. 
:(
    Опции темы
4ygynOK
Дата 10.10.2013, 17:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Есть вот такой вот код:
Код

BOOL CUGODatabaseMng::DeleteDir(DWORD BUGO_Id)
{
    ASSERT(m_pDatabaseMng);
    if (!m_pDatabaseMng)
        return FALSE;
    
    BOOL bParent = TRUE;
    BOOL bDelParent = TRUE;
    try
    {
        std::list<DWORD> lstIds;

        CString sSQL;
        sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);

        ADODB::_RecordsetPtr spRS = m_pDatabaseMng->OpenRecordset(sSQL);
        long nRecordCount = spRS->GetRecordCount();
        
        for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }
        
        if (nRecordCount > 1)
        {
            bParent = TRUE; // проверка наличия вложенных каталогов
        }

        spRS->Close();

        for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
        {
            if (bParent)
                bDelParent = FALSE; //если есть вложенные каталоги, то родительская не удаляется
            
            if (!DeleteDir(*it))
                return FALSE;
        }

        if (bDelParent)
        {
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
            return TRUE;
        }

    }
    catch (_com_error& e)
    {
        if (AfxMessageBox(CString(_T("Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description() + CString(_T("\nПродолжить удаление?")),MB_OKCANCEL) == IDOK)
        {
            return TRUE;
        }
        else return FALSE;
    }

    return FALSE;
}

предназначен для удаления директории используя базу данных.
 
Код

for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }

используется для составления списка.
Код

for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
        {
            if (!DeleteDir(*it))
                return FALSE;
                        if (bParent)
                bDelParent = FALSE; //если есть вложенные каталоги, то родительская не удаляется
        }

        if (bDelParent)
        {
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
            return TRUE;
        }

собственно для удаления каталогов.
Данный код можно использовать до уровня вложенности 2. Для меня стоит задача переделать его до любого уровня вложенности. Помогите пожалуйста все разъяснения дам без проблем.
PM MAIL   Вверх
bsa
Дата 10.10.2013, 23:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Сделай рекурсивную функцию, которая получает путь к каталогу и сначала вызывает себя рекурсивно для всех подкаталогов, а затем удаляет все файлы из указанного каталога и сам каталог, путь к которому передан параметром.
PM   Вверх
4ygynOK
Дата 11.10.2013, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



если можно то поподробнее, с приблизительным примером.
PM MAIL   Вверх
baldina
Дата 11.10.2013, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(4ygynOK @  10.10.2013,  17:14 Найти цитируемый пост)
Данный код можно использовать до уровня вложенности 2

почему? DeleteDir уже вызывает себя рекурсивно
PM MAIL   Вверх
4ygynOK
Дата 11.10.2013, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Цитата(baldina @ 11.10.2013,  13:40)
Цитата(4ygynOK @  10.10.2013,  17:14 Найти цитируемый пост)
Данный код можно использовать до уровня вложенности 2

почему? DeleteDir уже вызывает себя рекурсивно

Да но работает только до 2 уровня вложенности, вот сейчас ищу на каком моменте оно вываливается вместо того чтобы продолжить.
PM MAIL   Вверх
baldina
Дата 11.10.2013, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



последний  return FALSE; замени на TRUE
PM MAIL   Вверх
4ygynOK
Дата 11.10.2013, 17:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Цитата(baldina @ 11.10.2013,  15:05)
последний  return FALSE; замени на TRUE

Ничего не дает, если я правильно понял про return TRUE в самом конце после catch?
PM MAIL   Вверх
baldina
Дата 11.10.2013, 17:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



да. тут
Цитата

 if (!DeleteDir(*it))
                return FALSE;

ожидается, что в случае нормальной работы DeleteDir() возвращает TRUE. Погляди, на чем у тебя заканчивается - это либо данные из базы, либо DeleteDir() не в нужный момент FALSE   возвернул
PM MAIL   Вверх
4ygynOK
Дата 11.10.2013, 17:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Цитата(baldina @ 11.10.2013,  17:30)
да. тут
Цитата

 if (!DeleteDir(*it))
                return FALSE;

ожидается, что в случае нормальной работы DeleteDir() возвращает TRUE. Погляди, на чем у тебя заканчивается - это либо данные из базы, либо DeleteDir() не в нужный момент FALSE   возвернул

Удаление происходит но catch как я понимаю вызывается несколько раз. Так-как окошек выскакивает несколько прежде чем удалится.
PM MAIL   Вверх
baldina
Дата 11.10.2013, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



наверно это не хорошо. что в базе? что в e.Description()?

Добавлено через 2 минуты и 39 секунд
вот это странный фрагмент
Код

if (bParent)
                bDelParent = FALSE; //если есть вложенные каталоги, то родительская не удаляется

логика должна быть такая: сначала удалить потомков, потом себя. никаких проверок при этом не нужно
PM MAIL   Вверх
4ygynOK
Дата 11.10.2013, 18:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Цитата(baldina @ 11.10.2013,  18:00)
наверно это не хорошо. что в базе? что в e.Description()?

e.Description() - представляет собой сообщение из базы. В моем случае оно мне говорит что в папке есть связанные записи с такой-то таблицей. 
База, точнее таблица с которой мы работаем состоит из 4 столбцов ID(именно его мы потом засовываем в it там все по порядку), Parent_ID соответственно указывает на родительский ID, Name - имя папки, Number какое-то числовое значение, но насчет его сказали не парится.
вот ссылка на скрин с базы: http://s2.ipicture.ru/uploads/20131011/5HGGOmlv.bmp

Это сообщение отредактировал(а) 4ygynOK - 11.10.2013, 18:18
PM MAIL   Вверх
baldina
Дата 11.10.2013, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



тут что-то с логикой. 
убери строчки 25-28, 34-35: если есть вложенные папки, их надо удалить, что и делается в цикле. но сама папка не удаляется (из-за проверки и условия), поэтому не удается удалить и родительские. вобщем походу это просто лишнее.
PM MAIL   Вверх
4ygynOK
Дата 12.10.2013, 00:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Цитата(baldina @ 11.10.2013,  18:28)
тут что-то с логикой. 
убери строчки 25-28, 34-35: если есть вложенные папки, их надо удалить, что и делается в цикле. но сама папка не удаляется (из-за проверки и условия), поэтому не удается удалить и родительские. вобщем походу это просто лишнее.

Код

BOOL CUGODatabaseMng::DeleteDir(DWORD BUGO_Id)
{
    ASSERT(m_pDatabaseMng);
    if (!m_pDatabaseMng)
        return FALSE;
    
  
    try
    {
        std::list<DWORD> lstIds;
        CString sSQL;
        sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);
        ADODB::_RecordsetPtr spRS = m_pDatabaseMng->OpenRecordset(sSQL);
        long nRecordCount = spRS->GetRecordCount();
        
        for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }
        
        spRS->Close();
        for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
                          
            if (!DeleteDir(*it))
                return FALSE;
       
     
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
            return TRUE;
       
    }
    catch (_com_error& e)
    {
        if (AfxMessageBox(CString(_T("Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description() + CString(_T("\nПродолжить удаление?")),MB_OKCANCEL) == IDOK)
        {
            return TRUE;
        }
        else return FALSE;
    }
    return FALSE;
}

если сделать так то впринципе удаляется. Вот только не так как надо: допустим у нас есть один родительский каталог и 2 подкаталога, если мы можем удалить только один из двух подкаталогов, то этот код удалит этот 1 подкаталог, а ещё родительский впридачу, что делать не нужно, для этого я и организовал это условие. Вот как-то так пока. Спасибо baldina что помогаешь!!
PM MAIL   Вверх
akizelokro
Дата 12.10.2013, 07:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Если не делается, как советует baldina, то оберни твой цикл for(...) в цикл

while(lstIds.size() > 0)
{
// твой for, в котором ты будешь удалять каталоги, для которых не указан некий родительский, проверку на это надо будет
// тоже впихнуть. при удалении каталоги будешь удалять из контейнера соответствующий элемент.
}

Это сообщение отредактировал(а) akizelokro - 12.10.2013, 07:36


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
baldina
Дата 12.10.2013, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(4ygynOK @  12.10.2013,  00:21 Найти цитируемый пост)
 Вот только не так как надо: допустим у нас есть один родительский каталог и 2 подкаталога, если мы можем удалить только один из двух подкаталогов, то этот код удалит этот 1 подкаталог, а ещё родительский впридачу

нет. 
ф-ия DeleteDir(DWORD BUGO_Id) должна удалять BUGO_Id и его подкаталоги, но не родительский.
она сейчас так и делает:
Цитата(4ygynOK @  10.10.2013,  17:14 Найти цитируемый пост)
sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);

Цитата(4ygynOK @  10.10.2013,  17:14 Найти цитируемый пост)
sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);

так что все в порядке.
если есть два каталога (скажем с id 2 и 3) в родительском (id=1), и мы хотим удалить каталог с id=2, то вызываем DeleteDir(2). каталоги с id=1, id=3 останутся нетронутыми
PM MAIL   Вверх
4ygynOK
Дата 13.10.2013, 23:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Все дело в том что не удаляет, поэтому и сражаюсь. 

akizelokro, к сожалению использование while тоже ни к чему не привело.
PM MAIL   Вверх
4ygynOK
Дата 14.10.2013, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Ну что есть ещё какие-нибудь идеи?
PM MAIL   Вверх
baldina
Дата 14.10.2013, 14:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



4ygynOK, все идеи тебе уже высказали.
надо не пальцем в небо тыкать, а двигаться системно.
вот такой код
Код

BOOL CUGODatabaseMng::DeleteDir(DWORD BUGO_Id)
{
    ASSERT(m_pDatabaseMng);
    if (!m_pDatabaseMng)
        return FALSE;
    
    //BOOL bParent = TRUE;
    //BOOL bDelParent = TRUE;
    try
    {
        std::list<DWORD> lstIds;
        CString sSQL;
        sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);
        ADODB::_RecordsetPtr spRS = m_pDatabaseMng->OpenRecordset(sSQL);
        long nRecordCount = spRS->GetRecordCount();
        
        for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }
        
        //if (nRecordCount > 1)
        //{
        //    bParent = TRUE; // проверка наличия вложенных каталогов
        //}
        spRS->Close();
        for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
        {
            //if (bParent)
            //    bDelParent = FALSE; //если есть вложенные каталоги, то родительская не удаляется
            
            if (!DeleteDir(*it))
                return FALSE;
        }
        //if (bDelParent)
        {
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
            return TRUE;
        }
    }
    catch (_com_error& e)
    {
        if (AfxMessageBox(CString(_T("Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description() + CString(_T("\nПродолжить удаление?")),MB_OKCANCEL) == IDOK)
        {
            return TRUE;
        }
        else return FALSE;
    }
    return TRUE; //FALSE;
}

исполни, и напиши:
  • набор тестовых данных (содержимое базы)
  • способ вызова функции (что в параметрах)
  • возникают ли исключения, и если да - каков текст ошибки
  • если нет, по какому условию происходит досрочный выход

PM MAIL   Вверх
4ygynOK
Дата 14.10.2013, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



База до выполнения:
ID    PARENT_ID          NAME                       NUMBER_
0    0                     Библиотека                   11
63    0                        Э3                            54
64    0                        Э4                            55
65    0                        Э7                            56
66    63                        Test                              1
67    66                        Test1                              1
68    66                        Test2                              2
69    66                        Test3                              3
70    68                           1                              1
71    68                           2                              2
База после выполнения:
ID    PARENT_ID         NAME                      NUMBER_
0    0                        Библиотека        11
63    0                        Э3                        54
64    0                        Э4                        55
65    0                        Э7                        56
67    66                        Test1                         1
68    66                        Test2                         2
69    66                        Test3                         3
70    68                        1                                 1
71    68                        2                                 2

Исключение вызывается 6 раз, на BUGO_Id = 67, 70, 71, 68, 69, 66(не вызывается просто происходит удаление) и 63. Везде кроме 66 есть связанные записи, у 66 есть только подкаталоги со связанными записями.(Сделал в базе привязанную запись к 66, теперь удаляет, но все равно 6 раз выскакивает окно с ошибкой из catch).
В отладчике во вкладке Autos перед удалением:
        BUGO_Id     67                                                                       unsigned long
        sSQL    "DELETE FROM BUGO WHERE ID=67"    ATL::CStringT<char,StrTraitMFC_DLL
        e                     E_FAIL}    _                                                com_error &
после нажатия ОК во всплывающем окне из catch:
‡        AfxMessageBox returned                  1                                  int
+        e                                             {E_FAIL}                        _com_error &
+        this    0x03b802cc {m_pDatabaseMng=0x00467b6c m_pUGODBFolder=0x03b802fc m_Steck=[0]() ...}    KE_DB::CUGODatabaseMng * const

Для 66 записи из отладчика:
за 2 шага 

        BUGO_Id    66    unsigned long
+        m_pDatabaseMng    0x00467b6c  ID=66"    
+        this    0x03b802cc {m_pDatabaseMng=0x00467b6c m_pUGODBFolder=0x03b802fc m_Steck=[0]() ...}    KE_DB::CUGODatabaseMng * const

за 1 шаг 
‡        ATL::CHeapPtrBase<tagDBPROPSET,ATL::CComAllocator>::operator tagDBPROPSET * returned    0x01a1d1a8 {rgProperties=0x454c4544 cProperties=1176520020 guidPropertySet={...} }    tagDBPROPSET *
‡        KE_DB::CDatabaseMng::ExecuteSQL returned    true    bool
+        m_pDatabaseMng    0x00467b6c 
+        sSQL    "DELETE FROM BUGO WHERE ID=66"    
+        this    0x03b802cc   const

после вот что возвращается:
‡        KE_DB::CUGODatabaseMng::DeleteDir returned    1    int
+        it    66    
+        lstIds    [1](66)    
+        this    0x03b802cc  * const

Красных строчек нигде больше нет.

способ вызова функции (что в параметрах) - это откуда тебе сказать?

возникают ли исключения, и если да - каков текст ошибки(исключение вызывается 6 раз при таком коде, текст ошибки :
"Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description()="Невозможно выполнить каскадную операцию, поскольку наичие свзянных записей в таблице Images приведет к нарушению целостности данных." + CString(_T("\nПродолжить удаление?

PM MAIL   Вверх
baldina
Дата 14.10.2013, 17:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



да уж...

Цитата(4ygynOK @  14.10.2013,  16:27 Найти цитируемый пост)
способ вызова функции (что в параметрах) - это откуда тебе сказать?

с чего все начинается? DeleteDir(0) или DeleteDir(67) или еще как-то?

Цитата(4ygynOK @  14.10.2013,  16:27 Найти цитируемый пост)
Невозможно выполнить каскадную операцию, поскольку наичие свзянных записей в таблице Images приведет к нарушению целостности 

что это за таблица? если БД имеет ограничения, операции с базой должны им удовлетворять, например, прежде чем удалять из искомой таблицы, удалить из images (к логике работы DeleteDir() это относится боком)

В структуре БД явно есть косячок: 66 удаляется, оставляя висеть дочерние 67-69.

Итого: разговор переходит от DeleteDir(), логика которой концептуально верна, к обсуждению структуры базы.
Поэтому рассказывай какие там таблицы и как они связаны.

Добавлено через 4 минуты и 15 секунд
4ygynOK, сделай копию базы, оторви от этой таблицы все связи, убедись что все работает (должно!)
далее - добавь связь id <- parent_id. это предотвратит удаление родителей без удаления детей. DeleteDir() изменять не надо, она это уже учитывает
далее - восстанавливай связи по одной, внося изменения в DeleteDir() - добавляя код удаления связанных данных.

Добавлено через 4 минуты и 58 секунд
после каждого изменения проверяй, что оно все еще работает
PM MAIL   Вверх
4ygynOK
Дата 14.10.2013, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Вечером все выложу, если сможешь зайдешь глянешь.
PM MAIL   Вверх
4ygynOK
Дата 14.10.2013, 21:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Цитата

способ вызова функции (что в параметрах) - это откуда тебе сказать?
с чего все начинается? DeleteDir(0) или DeleteDir(67) или еще как-то?

Начинается все в зависимости от того на какую папку ты нажимаешь, собственно начинается все с её ID-шника.
Цитата

Итого: разговор переходит от DeleteDir(), логика которой концептуально верна, к обсуждению структуры базы.
Поэтому рассказывай какие там таблицы и как они связаны.

Сразу оговорюсь БД Access. Для нас я понимаю больше всего важны 3 таблицы BUGO(с которой мы работаем),UGO(именно с этой таблицей единственная связь таблицы BUGO, столбец ID из BUGO связывается  с BUGO_ID из UGO - связь один ко многим), и таблица IMAGES cвязанная с таблицей UGO тоже связь один ко многим по столбцам ID в UGO и UGO_REFERENCE в IMAGES.
 
PM MAIL   Вверх
4ygynOK
Дата 14.10.2013, 22:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Вот собственно база:

Присоединённый файл ( Кол-во скачиваний: 1 )
Присоединённый файл  testbase.7z 913,92 Kb
PM MAIL   Вверх
4ygynOK
Дата 14.10.2013, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Цитата

сделай копию базы, оторви от этой таблицы все связи, убедись что все работает (должно!)

тогда удаляется  сразу все. если разорвать эту связь.
Цитата

далее - добавь связь id <- parent_id.

честно не знаю как связать 2 столбца в одной таблице.
Остальное в процессе.

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  testbase.7z 913,92 Kb
PM MAIL   Вверх
baldina
Дата 15.10.2013, 00:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(4ygynOK @  14.10.2013,  21:54 Найти цитируемый пост)
Начинается все в зависимости от того на какую папку ты нажимаешь

чувствую себя тупицей....
ТЫ на какую папку нажимаешь? результаты какого теста приводились?
впрочем, сейчас это уже неактуально

Цитата(4ygynOK @  14.10.2013,  22:20 Найти цитируемый пост)
честно не знаю как связать 2 столбца в одной таблице

так же, как и в разных. наверно стоит начать хотя бы с минимального изучения БД, хотя бы в рамках Access, а потом уже программы для автоматизации писать... а то вдруг в результате какой-нибудь самолет пойдет под откос, или ракета с ядерной боеголовкой не туда наведется 

Цитата(4ygynOK @  14.10.2013,  22:20 Найти цитируемый пост)
тогда удаляется  сразу все. если разорвать эту связь.

т.е. таки работает функция, дело не в рекурсии и тд и тп

Цитата(4ygynOK @  14.10.2013,  21:54 Найти цитируемый пост)
я понимаю больше всего важны 3 таблицы

немного больше: почти все))))) не пугайся, не все, лишь 6: BUGO, UGO, IMAGES, CLAMPS_REFERENCES, OTHER_PRODUCES, FASTENER_IMAGES
в БД почти на всех связях установлено ограничение (контроль целостности), но мало где - каскадное обновление/удаление.
каскадное удаление решило бы проблему, но рекомендовать его включить нельзя, т.к. задача не ясна и неизвестно чем это аукнется.
лучший способ - попросить разработчика этой БД написать корректный запрос на удаление данных по BUGO_ID, им и пользоваться вместо 
Код

DELETE FROM BUGO WHERE ID=%d

походу разработчика не достать, придется писать самому. причем одним DELETE из всех таблиц сразу не удалить, только по одной. однако это уже вопросы раздела Access. а с С++ мы покончили: не считая проблем с sql, DeleteDir() работоспособная


Это сообщение отредактировал(а) baldina - 15.10.2013, 00:37
PM MAIL   Вверх
4ygynOK
Дата 15.10.2013, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Что в итоге получается: данный код не рабочий, он в принципе покрывает только частные случаи выкладываю тот что работает:
Код

BOOL CUGODatabaseMng::DeleteDir(DWORD BUGO_Id,BOOL* bDelete)
{
    ASSERT(m_pDatabaseMng);
    if (!m_pDatabaseMng)
        return FALSE;
    BOOL bDelete1 = TRUE;
    BOOL bDelete2 = TRUE;
    try
    {
        std::list<DWORD> lstIds;

        CString sSQL;
        sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);

        ADODB::_RecordsetPtr spRS = m_pDatabaseMng->OpenRecordset(sSQL);
        long nRecordCount = spRS->GetRecordCount();

        for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }

        spRS->Close();

        for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
        {
            if (!DeleteDir(*it, &bDelete1))
                return FALSE;

            if (bDelete1)
                bDelete2 = FALSE;
        }

        if (bDelete2)
        {
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
            return TRUE;
        }


    }
    catch (_com_error& e)
    {
        if (AfxMessageBox(CString(_T("Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description() + CString(_T("\nПродолжить удаление?")),MB_OKCANCEL) == IDOK)
        {
            *bDelete = FALSE; 
            return TRUE;
        }
        else return FALSE;
    }

    return FALSE;
}

данный код нормален, но удалять только может при вложенности до 2 каталогов. Как реализовать, чтобы была больше вложенность используя этот код? 
Либо можно сделать без добавления в функцию параметра, но это я уже не в курсе. 
Может подскажете как организовать большую вложенность?
PM MAIL   Вверх
baldina
Дата 15.10.2013, 15:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



использовать этот код неизменным можно только изменив структуру БД - сделав удаление каскадным для всех  связанных таблиц.
не изменяя БД заставить работать функцию можно только заменив 
Цитата(4ygynOK @  15.10.2013,  14:53 Найти цитируемый пост)
sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));

на последовательность удалений из связанных таблиц, т.е. реализовав каскадное удаление вручную.
других, простых путей нет.
и дело тут не в коде, он не содержит ограничений, а в необходимости удаления из БД, которое одним DELETE корректно не сделать.

Это сообщение отредактировал(а) baldina - 15.10.2013, 15:40
PM MAIL   Вверх
4ygynOK
Дата 15.10.2013, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Сказали что мне надо обрабатывать 3 ситуации, отсюда и 3 возвращаемых результата
1 - объект удален, а значит продолжаем удаление дальше, включая родительский объект
2 - объект не удален, но удаление продолжать (пользователь нажал "продолжить"), а значит продолжаем удаление, но родительский не удаляем
3 - объект не удален и удаление прервать (пользователь нажал "не продолжать") - прервать вообще операцию удаления.
и все это надо запихнуть в этот код
Код

BOOL CUGODatabaseMng::DeleteDir(DWORD BUGO_Id)
{
    ASSERT(m_pDatabaseMng);
    if (!m_pDatabaseMng)
        return FALSE;
    
    try
    {
        std::list<DWORD> lstIds;
        CString sSQL;
        sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);
        ADODB::_RecordsetPtr spRS = m_pDatabaseMng->OpenRecordset(sSQL);
        long nRecordCount = spRS->GetRecordCount();
        
        for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }
        
         spRS->Close();
        for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
        {
            
            if (!DeleteDir(*it))
                return FALSE;
        }
        
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
            return TRUE;
      
    }
    catch (_com_error& e)
    {
        if (AfxMessageBox(CString(_T("Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description() + CString(_T("\nПродолжить удаление?")),MB_OKCANCEL) == IDOK)
        {
            return TRUE;
        }
        else return FALSE;
    }
    return TRUE; //FALSE;
}

Вот как-то так. Мозги набекрень.
PM MAIL   Вверх
4ygynOK
Дата 15.10.2013, 17:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



При всем при этом вот этот код хороший:
Код

BOOL CUGODatabaseMng::DeleteDir(DWORD BUGO_Id,BOOL* bDelete)
{
    ASSERT(m_pDatabaseMng);
    if (!m_pDatabaseMng)
        return FALSE;
    BOOL bDelete1 = TRUE;
    BOOL bDelete2 = TRUE;
    try
    {
        std::list<DWORD> lstIds;

        CString sSQL;
        sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);

        ADODB::_RecordsetPtr spRS = m_pDatabaseMng->OpenRecordset(sSQL);
        long nRecordCount = spRS->GetRecordCount();
        
        for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }
    
        spRS->Close();

        for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
        {
            if (!DeleteDir(*it, &bDelete1))
            return FALSE;

            if (bDelete1)
                bDelete2 = FALSE;
        }
        
        if (bDelete2)
        {
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
            return TRUE;
        }
        
        
    }
    catch (_com_error& e)
    {
        if (AfxMessageBox(CString(_T("Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description() + CString(_T("\nПродолжить удаление?")),MB_OKCANCEL) == IDYES)
        {
            *bDelete = FALSE; 
            return TRUE;
        }
        else return FALSE;
    }

    return FALSE;
}

но как сказал мне на него начальник он некрасивый и работает только до каталогов вложенности 2. и надо сделать чтобы работал при любой вложенности. либо сделать с одним параметром DeleteDir(DWORD BUGO_Id) но тогда необходимо возвращать 3 значения.
PM MAIL   Вверх
4ygynOK
Дата 18.10.2013, 12:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Спасибо всем, решение прилагаю:
Код

int CUGODatabaseMng::DeleteDir(DWORD BUGO_Id)
{
    int nResult = 1;
    ASSERT(m_pDatabaseMng);
    if (!m_pDatabaseMng)
        return 0;
    
    try
    {
        std::list<DWORD> lstIds;

        CString sSQL;
        sSQL.Format(_T("SELECT ID FROM BUGO WHERE PARENT_ID=%d"), BUGO_Id);

        ADODB::_RecordsetPtr spRS = m_pDatabaseMng->OpenRecordset(sSQL);
        long nRecordCount = spRS->GetRecordCount();

        for (long nRecord = 0; nRecord < nRecordCount; ++nRecord)
        {
            lstIds.push_back((long)spRS->GetFields()->GetItem(_T("ID"))->GetValue());
            spRS->MoveNext();
        }

        spRS->Close();

        for (std::list<DWORD>::iterator it = lstIds.begin(); it != lstIds.end(); ++it)
        {
            int nChldResult = DeleteDir(*it);
            if (nChldResult == 0)
                return 0;

            if(nChldResult > 1)    // Если хоть одного потомка не удалили, то и сами не удаляемся
                nResult = nChldResult;
        }

        if (nResult == 1)
        {
            sSQL.Format(_T("DELETE FROM BUGO WHERE ID=%d"), BUGO_Id);
            VERIFY(m_pDatabaseMng->ExecuteSQL(sSQL));
        }
        return nResult;

    }
    catch (_com_error& e)
    {
        if (AfxMessageBox(CString(_T("Удаление каталога невозможно!\n")) + (LPCTSTR)e.Description() + CString(_T("\nПродолжить удаление?")),MB_OKCANCEL) == IDOK)
        {
            nResult = 2;
        }
        else 
            nResult = 0;
    }

    return nResult;
}

PM MAIL   Вверх
baldina
Дата 18.10.2013, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(4ygynOK @  18.10.2013,  12:20 Найти цитируемый пост)
решение прилагаю


и это решилось:
Цитата(4ygynOK @  15.10.2013,  17:09 Найти цитируемый пост)
работает только до каталогов вложенности 2. и надо сделать чтобы работал при любой вложенности

?
PM MAIL   Вверх
4ygynOK
Дата 18.10.2013, 17:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 10.10.2013

Репутация: нет
Всего: нет



Да вложенность может быть любой. 
baldina, тебе особая благодарность.
PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1535 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.