1515
Типичные вопросы [среда данных]
На этой станице помещены ответы на вопросы, которые я сам мучительно (или легко) находил, я не думаю, что ответы исчерпывающие, и если Вы найдёте, что что-нибудь дисанирует с Вашими представлениями, давайте обсудим и найдём лучшие решения... Кроме того, часто ответ может зависеть от версии как OS так и Visual FoxPro, проверить всё на всех версиях и платформах для меня просто непосильно. Изначально этот список был исключительно для VFP 5.0, в то время как сейчас это только VFP 7.0/8.0, я мог где-нибудь и пропустить упоминание о версии, и если Вы найдёте несоответствия, сообщите пожалуйста мне.

 

Вопрос: Почему триггер выдаёт ошибку? 

Ответ: Потому что на момент выполнения триггера данные, не удовлетворяют его требованиям. Для того, чтобы понять что именно происходит, лучше всего проследить соответствующий участок кода в отладчике. Без анализа конкретной ситуации можно предположить, что буферизация записей изменяемой таблица не соответствует логике внесения изменений, прописанных в коде. Например, Вы вставляете новую запись в таблицу, без использования свойств 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 я получаю несуществеющие ошибки. Имеется ли возможность сделать то, чего я хочу? 

Ответ: Действительно, ADO-ODBC VFP 6.0 имеет проблему, в том числе и не работает пример: http://msdn.microsoft.com/vfoxpro/downloads/download.asp?ID=025 , однако после установки http://msdn.microsoft.com/vfoxpro/downloads/download.asp?ID=027 проблема исчезает. И ещё: нужно регистрировать VFP-источник данных под System DSN в ODBC-Administrator.

Вопрос: При обращении к сохранённой процедуре я получаю ошибку о том, что процедура не найдена. Как правильно следует вызывать сохранённые процедуры? 

Ответ: Перед попыткой обращения к любой сохранённой процедуре из базы данных Вам следует сделать её активной, используя команду 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? 

Ответ: См. HOWTO: Pack a Table Through the Visual FoxPro ODBC Driver (VFPODBC.dll)
на http://support.microsoft.com/kb/q234756/

Вопрос: Возможно ли в VFP из программы добавлять/изменять/удалять в ODBC Администраторе DSN? 

Ответ: Все действия возможны через Win32Api используя SqlConfigDataSource из Odbccp32.dll и функции досупа к системному реестру:
  - для добавления см. [Q142216] HOWTO: Create ODBC Data Sources Using SqlConfigDataSource в MSDN
  - для чтения/изменения: см. [Q191638] HOWTO: Programmatically Access the Registry in Visual FoxPro ("ODBC Registry") в MSDN т.е. класс ODBCReg из HOME(2)+"classes\registry.prg" и пример в Solution.app в Win32Api "Read ODBC Regestry values" ("Sample Class Libraries" в MSDN)
  - для удаления см. [Q195262] HOWTO: Delete ODBC Data Source Using SqlConfigDataSource
см. также
  - [Q165866] How to Use File DSNs and DSN-less Connections
  - Примеры подключения различных Баз Данных через ADO (на www.relib.com)

Вопрос: Никак не могу получить полной 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, только бесполезно тренироваться...
 
 
Hosted by uCoz