Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ошибка TADODataSet.Locate! проверено в Delphi 6,7,9 
:(
    Опции темы
Петрович
  Дата 17.7.2005, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

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



Блин. Опять проблема с национальными настройками smile.
Есть программа:
Код
program TestLocate;
{$APPTYPE CONSOLE}
uses
  SysUtils,ADODB,ActiveX,ComObj;

const
  DatabaseName    = 'c:\TestDb.mdb';
  CLASS_DBEngine :TGUID ='{00000100-0000-0010-8000-00AA006D2EA4}';

var
  db :TADOConnection;
  ds :TADODataSet;

begin
  WriteLn('initialization');

  try
    CoInitialize(Nil);
    db := TADOConnection.Create(Nil);
    ds := TADODataSet.Create(Nil);

    db.LoginPrompt := False;

    WriteLn('Create database');
    if  FileExists(DatabaseName)  then  DeleteFile(DatabaseName);
    Variant(CreateOleObject(ClassIDToProgID(CLASS_DBEngine)))
      .Workspaces[0]
        .CreateDatabase (DatabaseName, ';LANGID=0x0409;CP=1252;COUNTRY=0', 0);


    db.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0'
                          +';Data Source="'+DatabaseName+'"'
                          ;

    WriteLn('Create Table');
    db.Execute('CREATE TABLE Test (fld decimal(15, 4))');
    db.Execute('INSERT INTO Test VALUES (1.123)');
    db.Execute('INSERT INTO Test VALUES (2.123)');
    db.Execute('INSERT INTO Test VALUES (3.123)');

    WriteLn('Open table');
    ds.Connection := db;
    ds.CommandText := 'SELECT * FROM Test';
    ds.Open;

    WriteLn('Show table');
    while not ds.Eof do begin
      WriteLn(ds.FieldByName('fld').AsString);
      ds.Next;
    end;

    Write('Locate 2.123 ');
    if  ds.Locate('fld',2.123,[])  then
      WriteLn('success')
    else
      WriteLn('fail');

    Write('Locate ''2.123'' ');
    if  ds.Locate('fld','2.123',[])  then
      WriteLn('success')
    else
      WriteLn('fail');

  except on e :Exception do begin
    WriteLn('Error:');
    WriteLn(e.ClassName);
    WriteLn(e.Message);
    end;
  end;

  FreeAndNil(ds);
  FreeAndNil(db);
  CoUninitialize;
  Write('Press <Enter> key for close application ...');  ReadLn;
end.

Так вот. Если в системе установлен разделитель дробной части '.' (точка) то все ок. Оба locate будут успешными. Но, если в системе установлен разделитель дробной части ',' (запятая) то беда. Первый locate не в состоянии найти существующую запись!

Т.е. если в таком случае (разделитель ','), нет возможности найти запись по значению вещественного поля!
Передавать значение в виде строки возможно не всегда.


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Grig
Дата 18.7.2005, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



В файле SysUtils.pas есть переменная DecimalSeparator.
Попробуй использовать ее.
Например:
Код

if DecimalSeparator = '.' then
begin
    if  ds.Locate('fld','2.123',[])  then    //Здесь точка
      WriteLn('success')    
    else    
      WriteLn('fail');
end;
if DecimalSeparator = ',' then
begin
    if  ds.Locate('fld','2,123',[])  then    //А здесь запятая
      WriteLn('success')    
    else    
      WriteLn('fail');
end;

Добавлено @ 11:29
Или во!
Еще круче:
Код

    if  ds.Locate('fld','2'+DecimalSeparator+'123',[])  then 
//......


Это сообщение отредактировал(а) Grig - 18.7.2005, 11:25


--------------------
        
PM MAIL ICQ   Вверх
Alex
Дата 18.7.2005, 11:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

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



В свое время писал:
Код

function FloatToStr2(Value: Extended): string;
var
  i: Integer;
  s: String;
begin
  s:= FloatToStr(Value);
  i:= Pos(',', s);
  if i = 0 then i:= Pos('.', s);
  if i > 0 then s[i]:= DecimalSeparator;
  Result:= s;
end;



--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
Петрович
Дата 18.7.2005, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

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



Ребята, вы меня не поняли.
ds.Locate('fld','2.123',[]) всегда сработает правильно не зависимо от текущего значения DecimalSeparator.
А вот ds.Locate('fld',2.123,[]), опять же вне зависимости от от текущего значения DecimalSeparator, может сработать, а может и не сработать. Все зависит от состояния настройки в системе! Причем, обратите внимание что второй параметр это значение типа Double (Currency, и т.п.).
Специально включил в пост полноценно работающий пример. Можете проверить.


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Петрович
Дата 18.7.2005, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

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



Разборки показали что это похоже косяк Microsoft!
У Borland'а, при обработке Locate, происходит преобразование всех числовых параметров в строку, в соответствии с текущими настройками системы (не DecimalSeparator!). Для этого используется функция VarToStr. А полученные значения передаются в COM-объекту Recordset в параметр Criteria метода Find. Так вот при выполнении этого метода, запись и не находится. Более того, когда таких параметров много (поиск по нескольким полям), я иногда наблюдал Exception ADO!
Ему видете-ли похоже всегда надо '.' давать.
Проверял и на MSACCESS, и на MS-SQL.
В MSDN об этом естествеенно ничего не сказано.
В принципе, если бы быть уверенным что Recordset.Find всегда требует '.' в качестве разделителя, то можно было бы подправить ADODB.pas, и выполнять преобразование не зависимо от текущих настроек системы.



--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Петрович
Дата 18.7.2005, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

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



Вот. Alex нашел сообщение об аналогичной проблемме http://coding.derkeiler.com/Archive/Delphi...04-03/0290.html


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Akella
Дата 18.7.2005, 15:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

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



тогда нужно на время работы программы или определённого куска кода (или формы) в системе (глобально) менять разделитель. Вернее Проверять, если не точка, то менять на точку. Пока другого выхода я не вижу.
PM MAIL   Вверх
Петрович
Дата 18.7.2005, 16:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

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



Цитата(dsergey @ 18.7.2005, 16:42)
... в системе (глобально) менять разделитель ...

Уж лучше тогда подправить ADODB.pas


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Akella
Дата 18.7.2005, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

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



продолжай
PM MAIL   Вверх
kobra
Дата 19.7.2005, 09:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 730
Регистрация: 15.6.2005
Где: Грузия, Тбилиси

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



Петрович мне кажется все так и должно быть.
попробуи в начало скрипта вставить
Код

DecimalSeparator := '.';

PM MAIL   Вверх
Alex
Дата 19.7.2005, 10:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

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



kobra, сам попробуй и увидишь, что это ни как не повлияет.


--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
kobra
Дата 19.7.2005, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 730
Регистрация: 15.6.2005
Где: Грузия, Тбилиси

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



извеняюс, не дописал
Код
DecimalSeparator := '.';
ds.Locate('fld',floattostr(2.123),[])  

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


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

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



Цитата(kobra @ 19.7.2005, 12:42)
извеняюс, не дописал
код Pascal/Delphi
DecimalSeparator := '.';
ds.Locate('fld',floattostr(2.123),[]) 

Блин. Ты сам-то пробовал smile


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
kobra
Дата 19.7.2005, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 730
Регистрация: 15.6.2005
Где: Грузия, Тбилиси

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



Цитата
Блин. Ты сам-то пробовал

да, все работает (по краинеи мере у меня).
PM MAIL   Вверх
Петрович
Дата 19.7.2005, 12:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

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



Цитата(dsergey @ 18.7.2005, 17:06)
продолжай

Да вариантов много. Вот например решение "в лоб".
В модуле ADODB.pas, надо подправить процедуру GetFilterStr.
Там есть case:
Код

    case Field.DataType of
      ftDate, ftTime, ftDateTime:
        QuoteCh := '#';
      ftString, ftFixedChar, ftWideString:
        begin
          if Partial and (Value <> '') then
          begin
            Value := Value + '*';
            Operator := ' like ';     { Do not localize }
          end;
          if Pos('''', Value) > 0 then
            QuoteCh := '#' else
            QuoteCh := '''';
        end;
    end;
Так вот, в него надо добавить еще одну веточку:
Код

      ftFloat, ftCurrency, ftBCD, ftFMTBcd:
        begin
          Value := AnsiReplaceStr(VarToStr(Value),GetLocaleChar(GetThreadLocale, LOCALE_SDECIMAL, '.'),'.');
        end;
Ну и в uses раздела implementation добавить StrUtils.

А вообще, все дело в том, что при выполнении преобразования Variant -> String, в некоторых случаях, в частности когда в Variant значение типа Currency, используется процедура преобразования из OS (в данном случае CurrToWStrViaOS).
Мне в принципе не понятно почему в одних случаях используется преобразование реализуемое Delphi, а в других, реализуемое OS. Но, это уже отдельная тема.


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Базы данных и репортинг"
Vit
Петрович

Запрещено:

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

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


Обязательно указание:

1. Базы данных (Paradox, Oracle и т.п.)

2. Способа доступа (ADO, BDE и т.д.)


  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • Вопросы по SQL и вопросы по базам данных не связанные с Дельфи задавать здесь

FAQ раздела лежит здесь!


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

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


 




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


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

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