1515
| | | Типичные вопросы [среда данных] |
- Почему триггер выдаёт ошибку?
- Как следует устанавливать режим буфферизации для источников данных формы?
- Почему могут возникнуть проблемы с удалением записей из таблицы, имеющей Primary Key?
- Почему создаваемые в Visual FoxPro таблицы не имеют кодовой страницы 1251?
- Я создал двухтабличный Local view с использованием ключевого слова Join из построителя View, а он не работает так, как я ожидал. В чём дело?
- Имеется ли простая возможность изменить месторасположение базы данных у FoxPro приложения?
- В VFP 6.0 при попытке получить соединение с таблицей базы данных Visual FoxPro через ADO-ODBC я получаю несуществеющие ошибки. Имеется ли возможность сделать то, чего я хочу?
- При обращении к сохранённой процедуре я получаю ошибку о том, что процедура не найдена. Как правильно следует вызывать сохранённые процедуры?
- В своём приложении я использую одну базу данных, и мне требуется открыть некоторую таблицу из другой, и у меня это не получается. Разве я не могу работать с несколькими базами данных?
- Вроде простая задача: например, есть таблица примерно такой структуры: Код клиента, дата оплаты, сумма. Коды клиента в таблице повторяются. Как можно одним запросом получить результат: Код клиента-дата последней оплаты сумма. А то приходится разбивать на два подзапрса -некрасиво :-(
- Имею VFP 6.0+SP3 VS6 и сейчас появился класс Session. Не покажете ли пример его использования?
- Я не создаю в базе объект Connection. Просто в коде делаю lnHndl = sqlconnect(lcDSN,lcLogin,lcPassw) и хотел бы предотвратить сообщение об ошибке, обрабатывать его программно. Как мне это сделать?
- Поставил VFP6.0, и хотя установлен "Prompt for code page" запроса не происходит :-(
В чем проблема?
- Можно ли выполнить команду PACK для таблицы через ODBC?
- Возможно ли в VFP из программы добавлять/изменять/удалять в ODBC Администраторе DSN?
- Никак не могу получить полной Rushmore оптимизации (SYS(3054) говорит, что оптимизация частиная) на таблице с единственным символьным полем. Чего бы это могло быть?
- Хотелось бы вести автоматически поле данных типа "дата последних изменений", однако в trigger update для таблицы этого у меня не получается. Почему и как это можно сделать?
- Как получить обновлённые данные в сетевом варианте изменения данных в случае использования Private Data Session?
Вопрос: Почему триггер выдаёт ошибку?
Ответ: Потому что на момент выполнения триггера данные, не удовлетворяют его требованиям. Для того, чтобы понять что именно происходит, лучше всего проследить соответствующий участок кода в отладчике. Без анализа конкретной ситуации можно предположить, что буферизация записей изменяемой таблица не соответствует логике внесения изменений, прописанных в коде. Например, Вы вставляете новую запись в таблицу, без использования свойств default value для полей, только намериваясь внести соответствующие изменения, а триггер уже отработал.
Вопрос: Как следует устанавливать режим буфферизации для источников данных формы?
Ответ: Лучший вариант: переустановить свойство Form.BufferMode окна в значение 2-Optimistic. В этом случае, если свойства Form.DataEnvironment.Cursor(i).BufferModeOverride у источников данных окна будут установлены в значение по умолчанию: 1-Use Form Setting (Default), то все отмеченные выше проблемы снимаются автоматически, впрочем Вы вольны устанавливать способ буферизации курсоров окна так, как найдёте нужным.
Вопрос: Почему могут возникнуть проблемы с удалением записей из таблицы, имеющей Primary Key?
Ответ: Данная проблема возникает потому, что не удаётся всегда уследить за корректной установкой системного режима Set Deleted в состояние On при использовании таблицы, а в состоянии Off конечно требования по уникальности значения Primary Key нарушаются. Чтобы устранить эту проблему следует индексам, соответствующим как Primary Key, так и Candidate назначить значение фильтра, содержащего выражение: Not Deleted(). Нужно иметь ввиду, что при этом не будет выполняться Rashmore оптимизация, поэтому сказанное выше приемлемо, если нет проблем производительности. В противном случае Вам следует подумать над возможностью снова использовать прежде помеченные к удалению записи (см. RECALL Command)
Вопрос: Почему создаваемые в Visual FoxPro таблицы не имеют кодовой страницы 1251?
Ответ: Это странно, если у Вас установлена руссифицированная версия Windows. Но в любом случае, нужно добиться того, чтобы значение, получаемое от функции Cpcurrent() было 1251. Если это на Вашей машине, достаточно выбрать пункт Tools/Options… и изменив режим Collate sequence в значение Russian на закладке Data, выполнить Set As Default. Далее, неплохо было бы пройтись по созданным Вами проектам и в каждом из них, открыв диалог Project Info…, на закладке Files выполнить пункт Update Native Code Page для отображения кодовых страниц файлов, включенных в проект. Программа Cpzero поможет Вам изменить кодовые страницы любых файлов со структурой DBF. Наконец, на клиентских машинах, использующих выполнимые файлы, следует попытаться обеспечить установку кодовой страницы путём добавления параметра: CODE PAGE=1251 в файлы Config.fpw в текущих каталогах этих исполняемых фалов.
Вопрос: Я создал двухтабличный Local view с использованием ключевого слова Join из построителя View, а он не работает так, как я ожидал. В чём дело?
Ответ: Microsoft Visual FoxPro 5.0a имеет проблему при создании Local view, содержащих ключевое слово Join: в список таблиц, следующих сразу за ключевым словом FROM, помещается полный список таблиц, участвующих в запросе, тогда как при наличии Join, требуется исключить из него те таблицы, которые используются непосредственно в Join. Далее, если в Join вовлечено более двух таблиц, то условия "соединения" записей, т.е. параметры ON, должны следовать сразу за соответствующими Join, в то время как построитель LocalView создаёт группу параметров ON в конце списка параметров Join. Мной написана утилита ModeView.exe, которая поможет Вам произвести соответствующую корректировку Local view базы данных, правда ею придётся пользоваться после любых изменений с сохранением ваших Local view, содержащих Join непосредственно перед их использованием в приложении [Получить копию ModeView.exe]. См. также
http://support.microsoft.com/kb/q157254/Вопрос: Имеется ли простая возможность изменить месторасположение базы данных у FoxPro приложения?
Ответ: Если речь идёт о свойстве Database у объектов CursorX в DataEnvironment форм и отчётов, то Вы можете легко его менять в runtime в событии DataEnvironment.BeforOpenTables() (по крайней мере начиная с версии 5.0) или в событии MyBaseForm.Load() установив MyForm.DataEnvironment.AutoOpenTables = .F. и воспользовавшись методом MyForm.DataEnvironment.OpenTables() явно. Вы также можете:
При новом месторасположении базы данных, в то время как её прежнее месторасположение уже недоступно, в среде редактирования последовательно открыть все формы и отчёты и на вопрос о невозможности открыть базу данных указать её новое месторасположение. Внесённые изменения следует, конечно, сохранить при выходе из диалога редактирования формы/отчёта.
Если предложенный вариант Вам кажется утомительным, Вы можете произвести соответствующие изменения, открыв файлы *.scx и *.frx "вручную". (См. для *.scx поля: Class и Properties, а для *.frx поля: Name и Expr. Вам необходимо отредактировать свойство Database у объекта Cursor).
Наконец последний вариант можно выполнить программно. Для этой цели мной написана утилита ChangeDb.exe. [Получить копию ChangeDb.exe]
Вопрос: В VFP 6.0 при попытке получить соединение с таблицей базы данных Visual FoxPro через ADO-ODBC я получаю несуществеющие ошибки. Имеется ли возможность сделать то, чего я хочу?
Вопрос: При обращении к сохранённой процедуре я получаю ошибку о том, что процедура не найдена. Как правильно следует вызывать сохранённые процедуры?
Ответ: Перед попыткой обращения к любой сохранённой процедуре из базы данных Вам следует сделать её активной, используя команду SET DATABASE TO dbc_name. Проблема может возникнуть и при компиляции, если в коде непосредственно прописано обращение к хранимой процедуре, а сама база данных не включена в проект. В этом случае достаточно дополнительно воспользоваться EXTERNAL ARRAY MyDbcFunction непосредственно в коде перед обращением к процедуре, чтобы объяснить эту особенность компилятору.
Вопрос: В своём приложении я использую одну базу данных, и мне требуется открыть некоторую таблицу из другой, и у меня это не получается. Разве я не могу работать с несколькими базами данных?
Ответ: Прежде всего, советую Вам посмотреть свойство Exclusive всех Cursor'ов в DataEnvironment Ваших форм и отчётов, посмотрите также значение параметра Open Exclusive в Tools\Options... на закладке Data, очень может быть, что эти параметры требуют открытия баз данных/таблиц в режиме Exclusive... Для открытия таблиц из кода следует делать что-нибудь подобно следующему:
IF !DBUSED("MyDbc")
OPEN DATABASE [full_path]MyDbc.dbc SHARED
IF !DBUSED("MyDbc")
?CHR(7)
MessageBox("Can not open database: MyDbc", 16, "Error")
RETURN .F.
ENDIF
ENDIF
SET DATABASE TO MyDbc
IF !INDBC("MyTable", "Table")
?CHR(7)
MessageBox("No table: MyTable in database: MyDbc", 16, "Error")
RETURN .F.
ENDIF
USE MyDbc!MyTable IN 0 SHARED
Вопрос: Вроде простая задача: например, есть таблица примерно такой структуры: Код клиента, дата оплаты, сумма. Коды клиента в таблице повторяются. Как можно одним запросом получить результат: Код клиента-дата последней оплаты сумма. А то приходится разбивать на два подзапрса -некрасиво :-(
Ответ: Где-нибудь так:
SELECT * FROM MyDbс!Payments p ;
WHERE STR(p.idclient) + DTOS(p.date) IN;
(SELECT STR(p.idclient) + DTOS(MAX(p.date));
FROM MyDbс!Payments p;
GROUP BY p.idclient)
... тоже как бы два в одном, а если для конкретного клиента, то можно так:
SELECT TOP 1 *;
FROM MyDbс!Payments p;
WHERE p.idclient = ?idclient;
ORDER BY p.date DESC
Вопрос: Имею VFP 6.0+SP3 VS6 и сейчас появился класс Session. Не покажете ли пример его использования?
Ответ: Как-нибудь примерно так:
#DEFINE C_DATABASE "D:\Program Files\Microsoft Visual Studio\";
+"MSDN\99OCT\1033\SAMPLES\VFP98\Tastrade\Data\Tastrade.dbc"
RELEASE goSec
PUBLIC goSec
goSec = CreateObject('MyclsSession')
DEFINE CLASS MyclsDE AS DataEnvironment
Comment = 'MyMultiUsedDEObject'
InitialSelectedAlias = 'Employee'
ADD OBJECT Cursor1 AS cursor WITH ;
Database = C_DATABASE, ;
Alias = 'Employee', ;
CursorSource = 'Employee', ;
Exclusive = .F.
* ...
PROCEDURE BeforeOpenTables
*... change if need
ENDPROC
ENDDEFINE
DEFINE CLASS MyclsSession AS Session
DataSession = 2
Name = 'MySession'
oDataEnvironment = NULL
FUNCTION Init
This.oDataEnvironment = CreateObject('MyclsDE')
IF VARTYPE(This.oDataEnvironment) = 'O'
This.oDataEnvironment.OpenTables()
ENDIF
ENDFUNC
ENDDEFINE
Обратите внимание, к моменту возникновения события MyclsDE.BeforeOpenTables() экземпляр объекта MyclsDE уже существует, и Вы можете из кода изменить его непосредственно перед открытием источников данных.
Нужно также иметь ввиду, что метод AddObject(...) контейнера и функция CreateObject(...) работают по разному:
1) метод This.AddObject('MySession') добавляя экземпляр класса Session к
контейнерам, имеющим св-во DataSession, - HИКОГДА и HИКАКИХ HОВЫХ DS не
создаёт... и действует так:
- если родительский объект имеет значение св-во DataSession = 2-Private DS,
то в DS этого самого родительского объекта.
- если родительский объект имеет значение св-во DataSession = 1-Default DS,
то в DS Default(1)
2) в свою очередь, поведение при создании экземпляра объекта класса Session
через CreateObject('MySession') несколько другое:
- если создаваемый объект имеет значение св-во DataSession = 2-Private DS,
то всегда создаётся новая DS, причём значение свойства MyForm.DataSessionID переустанавливается в значение последней созданной сессии.
- если создаваемый объект имеет значение св-во DataSession = 1-Default DS,
то в DS Default(1)
Вопрос: Я не создаю в базе объект Connection. Просто в коде делаю lnHndl = sqlconnect(lcDSN,lcLogin,lcPassw) и хотел бы предотвратить сообщение об ошибке, обрабатывать его программно. Как мне это сделать?
Ответ: Попробуйте выполнить
=SQLSETPROP(0,"DispWarnings", .F.)
=SQLSETPROP(0,"DispLogin", 3) && DB_PROMPTNEVER
Вопрос: Поставил VFP6.0, и хотя установлен "Prompt for code page" запроса не происходит :-(
В чем проблема?
Ответ: Читайте внимательно в MSDN раздел "SET CPDIALOG"... и там написано:
ON - (Default) Displays the Code Page dialog box when you open a table
and the following conditions are true:
- The table is opened exclusively.
- The table is not marked with a code page.
Другими словами зачем вызывать диалог, если поменять кодовую страницу
всё равно не получится :-)
Вопрос: Можно ли выполнить команду PACK для таблицы через ODBC?
Вопрос: Возможно ли в VFP из программы добавлять/изменять/удалять в ODBC Администраторе DSN?
Вопрос: Никак не могу получить полной Rushmore оптимизации (SYS(3054) говорит, что оптимизация частиная) на таблице с единственным символьным полем. Чего бы это могло быть?
Ответ: Попробуйте установить SET DELETED OFF перед выполнением SQL-SELECT :-) ... Если в последнем случае получите полную оптимизацию, то попробуйте добавить индекс INDEX ON DELETED() TAG DEL в Вашу таблицу ... Теперь, как надеюсь, оптимизация будет полной и при SET DELETED ON
Вопрос: Хотелось бы вести автоматически поле данных типа "дата последних изменений", однако в trigger update для таблицы этого у меня не получается. Почему и как это можно сделать?
Ответ: К сожалению в Update trigger невозможно сделать изменения в записи, по поводу которой он вызван, поскольку бесконечная рекурсия :-( и в Update trigger возможно только внести изменения в другую таблицу, имеющую связь с исходной типа один-к-одному. В противном случае Вы можете это сделать:
- в Record Rule для таблицы вызвать ХП
- в MyBaseForm.Save()
- в событиях Valid() соответствующих контролов
Вопрос: Как получить обновлённые данные в сетевом варианте изменения данных в случае использования Private Data Session?
Ответ: Действительно, в процессе на стороне клиента интервалом обновления данных рулит второй параметр в SET REFRESH , т.е раньше этого значения (если не использовать SYS(1104) [в VFP 6.0 см. Q269284 Knowledge Base Articles INFO: Undocumented Function SYS(1104) или VFP 7.0], которая производит обновления в момент выполнения... ну или REQUERY() в случае Remote View/SELECT :-) получить новые значения невозможно.
Далее, если кэшь даже и обновлена (явно через SYS(1104), или прошёл интервал, указанный вторм параметром в SET REFRESH), то в любом случае, чтобы обновлённые данные в текущей записи стали "реально новыми", требуется "дёрнуть" за указатель записи (типа GO (RECNO('ChangedTable')) IN ChangedTable)
Другими словами, выполнять GO (RECNO('ChangedTable')) IN ChangedTable (или как-то иначе выудить новые значения, например Refresh() для "присоединённых данных") раньше чем не истёк интервал, указанный в качестве второго параетра в SET REFRESH, для VFP 5.0, только бесполезно тренироваться...