Показать сообщение отдельно
Старый 03.07.2009, 06:19   #4  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
365 / 542 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
->
Цитата:
Сообщение от Dron AKA andy Посмотреть сообщение
... После непродолжительных размышлений над оригинальным кодом я заметил некую странность: мы сначала наполняем контейнер названиями полей в SQL-интерпретации через
X++:
dictTable.fieldName(this.field(i), DbBackend::SQL)
, а затем повторно получаем названия тех же полей, но уже чуть видоизмененным способом:
X++:
dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy)
Буду рад, если кто-нибудь мне объяснит, почему сделано именно так ...
Для MS SQL Server разницы в вызове dictTable.fieldName(...) c параметром fieldNameGenerationMode по-умолчанию или со значением fieldNameGenerationMode::FieldListGroupBy нет никакой(по крайней мере я ее не замечал), а вот для Oracle разница существенная.

В случае, наличия в индексе строкового поля, при вызове dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) ядро AX преобразует поля к одному регистру, добавляя вызов substr и nls_lower.

Т.е. в AX 3.0 для СУБД Oracle вызов dictTable.fieldName(this.field(i), DbBackend::SQL) для строкового поля вернет field, а вызов dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) - вернет
substr(nls_lower(field), 1, strlen(field)).

В конфигурации АОСа AX4.0 есть параметр -
Database Tuning\AutoGeneration Options\Include SUBSTR and LOWER in all SELECT statements to support Oracle mixed-case systems, который видимо и отвечает за генерацию данного substr и nls_lower.

В итоге, если в таблице есть значения строкового поля 'SSS' и 'sss', данное поле включено в индекс и используемая СУБД Oracle, то замена

X++:
dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy)
на

X++:
dictTable.fieldName(this.field(i), DbBackend::SQL)
приведет к тому, что при использовании пункта 'Дубликаты' - появится инфолог - 'Дубликатов нет'. А при попытке сделать индекс уникальным, вывалится ошибка, о не возможности его создания, поскольку ядро AX при создании индекса на Oracle использует все те же substr и nls_lower

В связи с этим, привожу немного измененный код(для AX 3.0, аналогичные изменения можно внести и для AX 4.0), который одинаково работает как на SQL, так и на Oracle.

X++:
void showDuplicates()
{
    tableId         tableId         = this.tableid();
    DictTable       dictTable       = new DictTable(tableId);
    boolean         dataPrCompany   = dictTable.dataPrCompany();
    container       fields;
    Counter         numberOfFields  = this.numberOfFields();
    Counter         i;
    str             stmtStr;
    str             resultLineStr;
    str             resultField;
    str             resultField1;
    UserConnection  con             = new UserConnection();
    Statement       stmt            = con.createStatement();
    ResultSet       resultSet;
    boolean         anyDuplicates   = false;
    ;
    if (dataPrCompany)
        fields += dictTable.fieldname(fieldnum(common,DataAreaId),DbBackend::SQL);
    for (i = 1; i <= numberOfFields; i++)
    {
        fields += dictTable.fieldName(this.field(i), DbBackend::SQL);
    }
    //srf -->
    //if (dataPrCompany)
    //    numberOfFields++;
    //srf <--
    stmtStr = 'select count(*)';
    //srf -->
    if (dataPrCompany)
    {
        stmtStr += ', ' + dictTable.fieldName(fieldnum(Common,DataAreaId),DbBackend::Sql,0,FieldNameGenerationMode::FieldListGroupBy);
    }
    //srf <--
    for (i = 1; i <= numberOfFields; i++)
    {
        stmtStr += ', ' + dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy);
    }
    stmtStr += ' from ' + dictTable.name(DbBackend::SQL);
    stmtStr += ' group by ';
    //srf -->
    if (dataPrCompany)
    {
        stmtStr += dictTable.fieldName(fieldnum(Common,DataAreaId),DbBackend::Sql,0,FieldNameGenerationMode::FieldListGroupBy);
        if (numberOfFields >= 1)
        {
            stmtStr+= ', ';
        }
    }
    //srf <--
    for (i = 1; i <= numberOfFields; i++)
    {
        if (i > 1)
            stmtStr += ', ';
        stmtStr += dicttable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::GroupByFieldList);
    }
    //srf -->
    if (dataPrCompany)
        numberOfFields++;
    //srf <--
    stmtStr += ' having count(*) > 1';
    if (numberOfFields > 0)
    {
        stmtStr += ' order by ';
        for (i = 1; i <= numberOfFields; i++)
        {
            if (i > 1)
                stmtStr += ', ';
            stmtStr += int2str(i+1);
        }
        stmtStr += ' desc';
    }
    resultSet = stmt.executeQuery(stmtStr);
    while (resultSet.next())
    {
        resultLineStr = "@SYS283" + strFmt(': %1', resultSet.getString(1));
        for (i = 1; i <= numberOfFields; i++)
        {
            resultField = strLtrim(resultSet.getString(i+1));
            if (i == 1 && dataPrCompany)
                resultField1 = resultField;
            else
                resultLineStr += strFmt(', %1: \'%2\'', conPeek(fields, i), resultField);
        }
        if (dataPrCompany)
            setPrefix(strFmt('%1: %2', conPeek(fields, 1), resultField1));
        info(resultLineStr);
        anyDuplicates = true;
    }
    if (!anyDuplicates)
        info("@SYS68671");
}
P.S. Кстати данную функцию починили в AX2009, а параметр Database Tuning\AutoGeneration Options\Include SUBSTR and LOWER in all SELECT statements to support Oracle mixed-case systems в конфигурации АОСа отсутсвует.
За это сообщение автора поблагодарили: tricky (1).