![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как настрить МастерДетайл виды в QuantumGrid v.4 через TADOQuery [D6, Win2k]
mvg_first © (2002-10-28 21:46:00)Вышел значит недвано новая версия Quantum Grid от DevExpress. И вней есть такая очень красивая возможность по реализации несколькоих Мастер-Дейил отношений в одном гриде. У кого нибудь получилось уже настроить нормальную работу используюя TADOQuery и параметризированные запросы.
Во всех моих попытках получался глюк выражающийся в отражении одинаковых изменений во всех детаилах при редактировании данных в одном из них. Никто не сталкивался с такой проблемой? Как с этим бороться?
vuk (2002-10-30 15:05:00) [1]>А можно ли считать багом то что в GridMode = True не работает
>мастер детаил???
Не знаю, пока с этим вопрос не ясен, в ньюсгруппе у DevExpress уже есть сообщения по этому поводу...
Результат (если он будет) можно будет смотреть там же. Пока же нужно еще на это время найти.
mvg_first (2002-10-30 14:59:00) [2]Все таки я добился своего !!! Хоть кто то баг подтвердил.
А можно ли считать багом то что в GridMode = True не работает мастер детаил???
И если можно, результат общения мне на мыло mvgfirst@nm.ru если не затруднит.
Заранее спасибо :)
vuk (2002-10-30 14:47:00) [3]Да, действительно, баг присутствует, я просто даже сначала на него внимания не обратил. Надо будет багрепорт отправить...
mvg_first (2002-10-30 12:18:00) [4]Уточню данные, изменения отражаются не обязательно в первой строке, если допустим в первом детаиле переместится на 3-ю запись а потом перейти на второй детаил и сделать изменения в первой (или во второй или в любой) записи то изменения отразятся в первом детаиле в той строке в которой мы находились перед тем как перешли во втрой детаил.
Причем строка первого детаила (который как бы не активный) выглядит совершенно точно по всем полям так же как и строка второго детаила которую мы только что изменили.
Если перейти обратно в первый детаил все становится на свои места :) Значения возвращаются в норму :).
mvg_first (2002-10-30 12:11:00) [5]Вообщем как я и предполагал, глюк остался :)
Как повторить чтоб было понятнее.
Пример скомпилил без изменений (только подправил имя сервера)
Запустил, все заработало, гриды открываются, как положено.
Нажал, на "плюсик" в строке с CategoryId = 4
и так же нажал на "плюсик" в строке с CategoryId = 5
Передо мной картина из двух вложенных таблиц содержащих совершенно разные данные. Как и должно быть. Т.е. пока все нормально.
После чего изменяю знчение в колонке UnitPrice второго детаила в первой строке. После изменения нажимаю Enter и вижу ту же значение в первой строке первого детаила. В результате - явная бочина. Может это так и должно быть??? Но я никогда не докажу этого пользователям моей программы :)
vuk (2002-10-29 20:13:00) [6]Когда будете смотреть, обратите внимания на два обычных (TDBGrid) грида внизу формы. Они там для того, чтобы было видно, что происходит с наборами данных при навигации по QG.
mvg_first (2002-10-29 20:08:00) [7]Ок, пример себе скопировал, но посмотрю уже завтра. И вопросы понятное дело завтра продолжаться :)
vuk (2002-10-29 18:25:00) [8]продолжение unit1.dfm
object ADOConnection1: TADOConnection
Connected = True
ConnectionString =
"Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In" +
"fo=False;Initial Catalog=Northwind;Data Source=FCS---S05"
LoginPrompt = False
Provider = "SQLOLEDB.1"
Left = 32
Top = 70
end
object qryCategories: TADOQuery
Connection = ADOConnection1
CursorType = ctStatic
Parameters = <>
SQL.Strings = (
"SELECT CategoryID, CategoryName, Description, Picture"
"FROM Categories")
Left = 32
Top = 98
object qryCategoriesCategoryID: TAutoIncField
FieldName = "CategoryID"
ReadOnly = True
end
object qryCategoriesCategoryName: TWideStringField
FieldName = "CategoryName"
Size = 15
end
object qryCategoriesDescription: TMemoField
FieldName = "Description"
BlobType = ftMemo
end
object qryCategoriesPicture: TBlobField
FieldName = "Picture"
end
end
object qryProducts: TADOQuery
Connection = ADOConnection1
CursorType = ctStatic
Parameters = <
item
Name = "Category"
DataType = ftString
Size = 4
Value = Null
end>
SQL.Strings = (
"SELECT ProductID, ProductName, SupplierID, "
" CategoryID, QuantityPerUnit, UnitPrice,"
" UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued"
"FROM Products"
"WHERE CategoryID = :Category")
Left = 32
Top = 126
object qryProductsProductID: TAutoIncField
FieldName = "ProductID"
ReadOnly = True
end
object qryProductsProductName: TWideStringField
FieldName = "ProductName"
Size = 40
end
object qryProductsSupplierID: TIntegerField
FieldName = "SupplierID"
end
object qryProductsCategoryID: TIntegerField
FieldName = "CategoryID"
end
object qryProductsQuantityPerUnit: TWideStringField
FieldName = "QuantityPerUnit"
end
object qryProductsUnitPrice: TBCDField
FieldName = "UnitPrice"
Precision = 19
end
object qryProductsUnitsInStock: TSmallintField
FieldName = "UnitsInStock"
end
object qryProductsUnitsOnOrder: TSmallintField
FieldName = "UnitsOnOrder"
end
object qryProductsReorderLevel: TSmallintField
FieldName = "ReorderLevel"
end
object qryProductsDiscontinued: TBooleanField
FieldName = "Discontinued"
end
end
object dsCategories: TDataSource
DataSet = qryCategories
Left = 60
Top = 98
end
object dsProducts: TDataSource
DataSet = qryProducts
Left = 60
Top = 126
end
end
vuk (2002-10-29 18:24:00) [9]unit1.dfm
object Form1: TForm1
Left = 347
Top = 151
Width = 605
Height = 460
Caption = "Form1"
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = "MS Sans Serif"
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object cxGrid1: TcxGrid
Left = 0
Top = 0
Width = 597
Height = 193
Align = alClient
TabOrder = 0
object tvCategories: TcxGridDBTableView
DataController.DataSource = dsCategories
DataController.DetailKeyFieldNames = "CategoryID"
DataController.Filter.Criteria = {00000000}
DataController.KeyFieldNames = "CategoryID"
DataController.Summary.DefaultGroupSummaryItems = <>
DataController.Summary.FooterSummaryItems = <>
DataController.Summary.SummaryGroups = <>
OptionsBehavior.ImmediateEditor = False
object tvCategoriesCategoryID: TcxGridDBColumn
DataBinding.FieldName = "CategoryID"
end
object tvCategoriesCategoryName: TcxGridDBColumn
DataBinding.FieldName = "CategoryName"
end
object tvCategoriesDescription: TcxGridDBColumn
DataBinding.FieldName = "Description"
end
object tvCategoriesPicture: TcxGridDBColumn
DataBinding.FieldName = "Picture"
end
end
object tvProducts: TcxGridDBTableView
DataController.DataModeController.DetailInSQLMode = True
DataController.DataModeController.OnDetailFirst = ReopenProducts
DataController.DataModeController.OnDetailIsCurrentQuery = CheckProductsDS
DataController.DataSource = dsProducts
DataController.DetailKeyFieldNames = "CategoryID"
DataController.Filter.Criteria = {00000000}
DataController.KeyFieldNames = "ProductID"
DataController.MasterKeyFieldNames = "CategoryID"
DataController.Summary.DefaultGroupSummaryItems = <>
DataController.Summary.FooterSummaryItems = <>
DataController.Summary.SummaryGroups = <>
OptionsBehavior.ImmediateEditor = False
object tvProductsProductID: TcxGridDBColumn
DataBinding.FieldName = "ProductID"
end
object tvProductsProductName: TcxGridDBColumn
DataBinding.FieldName = "ProductName"
end
object tvProductsSupplierID: TcxGridDBColumn
DataBinding.FieldName = "SupplierID"
end
object tvProductsCategoryID: TcxGridDBColumn
DataBinding.FieldName = "CategoryID"
end
object tvProductsQuantityPerUnit: TcxGridDBColumn
DataBinding.FieldName = "QuantityPerUnit"
end
object tvProductsUnitPrice: TcxGridDBColumn
DataBinding.FieldName = "UnitPrice"
end
object tvProductsUnitsInStock: TcxGridDBColumn
DataBinding.FieldName = "UnitsInStock"
end
object tvProductsUnitsOnOrder: TcxGridDBColumn
DataBinding.FieldName = "UnitsOnOrder"
end
object tvProductsReorderLevel: TcxGridDBColumn
DataBinding.FieldName = "ReorderLevel"
end
object tvProductsDiscontinued: TcxGridDBColumn
DataBinding.FieldName = "Discontinued"
end
end
object lvCategories: TcxGridLevel
GridView = tvCategories
object lvProducts: TcxGridLevel
GridView = tvProducts
end
end
end
object DBGrid1: TDBGrid
Left = 0
Top = 313
Width = 597
Height = 120
Align = alBottom
DataSource = dsProducts
TabOrder = 1
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = "MS Sans Serif"
TitleFont.Style = []
end
object DBGrid2: TDBGrid
Left = 0
Top = 193
Width = 597
Height = 120
Align = alBottom
DataSource = dsCategories
TabOrder = 2
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = "MS Sans Serif"
TitleFont.Style = []
end
vuk (2002-10-29 18:22:00) [10]Собственно пример. D6 + ADO. Сначала модуль, потом файл формы.
Необходимо поправить ConnectionString.
unit1.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, cxStyles, cxCustomData, cxGraphics, cxFilter, cxData, cxEdit,
DB, cxDBData, cxGridLevel, cxClasses, cxControls, cxGridCustomView,
cxGridCustomTableView, cxGridTableView, cxGridDBTableView, cxGrid, ADODB,
Grids, DBGrids;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
qryCategories: TADOQuery;
qryProducts: TADOQuery;
dsCategories: TDataSource;
dsProducts: TDataSource;
tvCategories: TcxGridDBTableView;
lvCategories: TcxGridLevel;
cxGrid1: TcxGrid;
qryCategoriesCategoryID: TAutoIncField;
qryCategoriesCategoryName: TWideStringField;
qryCategoriesDescription: TMemoField;
qryCategoriesPicture: TBlobField;
qryProductsProductID: TAutoIncField;
qryProductsProductName: TWideStringField;
qryProductsSupplierID: TIntegerField;
qryProductsCategoryID: TIntegerField;
qryProductsQuantityPerUnit: TWideStringField;
qryProductsUnitPrice: TBCDField;
qryProductsUnitsInStock: TSmallintField;
qryProductsUnitsOnOrder: TSmallintField;
qryProductsReorderLevel: TSmallintField;
qryProductsDiscontinued: TBooleanField;
lvProducts: TcxGridLevel;
tvProducts: TcxGridDBTableView;
tvCategoriesCategoryID: TcxGridDBColumn;
tvCategoriesCategoryName: TcxGridDBColumn;
tvCategoriesDescription: TcxGridDBColumn;
tvCategoriesPicture: TcxGridDBColumn;
tvProductsProductID: TcxGridDBColumn;
tvProductsProductName: TcxGridDBColumn;
tvProductsSupplierID: TcxGridDBColumn;
tvProductsCategoryID: TcxGridDBColumn;
tvProductsQuantityPerUnit: TcxGridDBColumn;
tvProductsUnitPrice: TcxGridDBColumn;
tvProductsUnitsInStock: TcxGridDBColumn;
tvProductsUnitsOnOrder: TcxGridDBColumn;
tvProductsReorderLevel: TcxGridDBColumn;
tvProductsDiscontinued: TcxGridDBColumn;
DBGrid1: TDBGrid;
DBGrid2: TDBGrid;
procedure ReopenProducts(
Sender: TcxDBDataModeController; ADataSet: TDataSet;
const AMasterDetailKeyFieldNames: String;
const AMasterDetailKeyValues: Variant; var AReopened: Boolean);
function CheckProductsDS(
Sender: TcxDBDataModeController; ADataSet: TDataSet;
const AMasterDetailKeyFieldNames: String;
const AMasterDetailKeyValues: Variant): Boolean;
procedure FormCreate(Sender: TObject);
private
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ReopenProducts(
Sender: TcxDBDataModeController; ADataSet: TDataSet;
const AMasterDetailKeyFieldNames: String;
const AMasterDetailKeyValues: Variant; var AReopened: Boolean);
begin
with (ADataSet as TADOQuery) do
begin
if Parameters.ParamValues["Category"] = AMasterDetailKeyValues then
begin
First;
Exit;
end;
DisableControls;
try
Active := False;
Parameters.ParamValues["Category"] := AMasterDetailKeyValues;
Active := True;
finally
EnableControls;
end;
AReopened := True;
end;
end;
function TForm1.CheckProductsDS(
Sender: TcxDBDataModeController; ADataSet: TDataSet;
const AMasterDetailKeyFieldNames: String;
const AMasterDetailKeyValues: Variant): Boolean;
begin
Result := false;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
qryCategories.Open;
qryProducts.Open;
end;
end.
vuk (2002-10-29 14:58:00) [11]Оно не сложно, в принципе, я его уже сделал, просто я сейчас занят на работе... Там только одна тонкость вылезла, которой сразу не заметил (возможно это небольшой баг). Дело в том, что уже загруженный подчиненный набор данных переоткрывается не при активизации соответствующего GridView, а только после навигации по записям в нем.
Пример будет чуть позжее...
mvg_first (2002-10-29 13:57:00) [12]Алло vukтак где же пример? Или очень сложно?
mvg_first (2002-10-29 12:34:00) [13]БД у меня MSSQL 7.0 Насчет примера возражать не буду. Так что б уж совесем все понятно стало.
Может у меня версия QG4 не корректная :) Надо бы сверить :) У меня версия 1.0.0.0
vuk (2002-10-29 12:22:00) [14]У Вас BD какая? Если MSSQL, то могу попробовать набросать пример на демонстрационной базе MS и сюда выложить...
mvg_first (2002-10-29 12:17:00) [15]Все стоит правильно.
Первая таблица - Все по умолчанию, только установил DataSource на TAdoQuery с запросом SELECT * FROM TovTab (т.е. полная выборка) это таблица мастер. У нее же установил DetailInSQLMode=true.
Добавил подуровень и в в нем в установил DataSource на TAdoQuery с запросом SELECT * FROM DocTab WHERE IdTov = :ID_TOV (т.е. параметризированный запрос).
Свойство DetailKeyFieldNamesУстановил на поле IdTov - в моей таблице указывает на идентификатор товара
Свойство MasterKeyFieldNamesустановил на поле ID - поле из первой таблицы указывает на уникальный идентификатор товара
Свойство KeyFieldNamesустановил на поле ROW_ID - поле второй таблицы указывает на уникальный идентификторо строки во втрой таблице
vuk (2002-10-29 12:04:00) [16]to mvg_first:
>Нмчего не помогает, я даже больше скажу.
У меня такого не было. Все работает как часы (если не в GridMode).
>А вы это сами проверяли? У меня вот не сработало почему то :(
А то как же? Вот только что еще раз проверил. Все работает как и должно.
А у Вас свойства KeyFieldNames/ MasterKeyFieldNames/ DetailKeyFieldNames правильно установлены?
mvg_first (2002-10-29 11:47:00) [17]
> который определяет, является ди текущий набор данных в подчиненном
> наборе данных именно тем набором, который нужно отобразить.
> Проверяется это по значениям пареметров (в принципе, можног
> и не проверять, а просто вернуть false).
А вы это сами проверяли? У меня вот не сработало почему то :(
mvg_first (2002-10-29 11:46:00) [18]Нмчего не помогает, я даже больше скажу. Только что внимательнее присмотрелся к поведению Детаил-грида. У меня стоят параметры по умолчанию, т.е. ДатаСет в авторедактировании, у грида стоит опция "сразу показывать редактор". Так вот, открываю первый детаил грид в нем допустим 5 строк, на первой записи в колонке цена указано 0,91 на второй вижу 0,86 при перемещении фокуса на вторую строку в ней значение меняется на 0,91. Т.е. значение берется из первой записи, и так при хождении по всем строкам :(
Это 100% глюк. Если это не так, скажите как сделать правильно.
Второй глюк который я заметил - это если не ставить галку в свойстве DetailInSQLMode и организовывать мастердетаил используюя TAdoQuery то в детаилах отображается только первая запись хотя их конкретно больше.
Вот такой глюк.
vuk (2002-10-29 11:13:00) [19]to Ученик:
>тут ведь вот было: GridMode=False для Master, все показывается
>нормально, GridMode=True, подчиненные таблицы пустые :(
Похоже все-таки да, не работает это все в GridMode. Что это, особенность работы или баг, пока не знаю, надо будет DevExpress трясти на эту тему...
to mvg_first:
>Давайте расставим точки над и.
Вы поняли все совершенно верно.
Там же есть нужно написать обработчик OnDetailIsCurrentQuery, который определяет, является ди текущий набор данных в подчиненном наборе данных именно тем набором, который нужно отобразить. Проверяется это по значениям пареметров (в принципе, можног и не проверять, а просто вернуть false). Возможно это решит проблему.
mvg_first (2002-10-29 10:32:00) [20]Более подробно опишу пример на котором у меня не работает Мастер-Детаил.
Есть две таблицы одна - "Таблица товаров" вторая таблица документов по которым этот товар приходил. Обе достаточно большие больше 10000 записей. Вернее в первой таблице их около 2000 во второй соответственно что то около 20 000. Т.е. открытие этих таблиц полностью занятие достаточно геморойное, как вы понимаете.
По этому написал пример в котором Использую параметрический запрос, все сделал как описано в Хелпе. Даже обработал событие OnDetailFirst, что бы обрабатывать установку параметра для фильрования записей.
Запрос ко второй таблице выглядит так
SELECT * FROM TabDoc WHERE IdTov = :ID_TOV
В обработчике указанного события выполняю переоткрытие таблицы
with (ADataSet as TADOQuery) do
begin
DisableControls;
try
Active := False;
Parameters.ParamByName("ID_TOV").Value := AMasterDetailKeyValues;
Active := True;
finally
EnableControls;
end;
AReopened := True;
end;
В результате вполне красиво по "плюсику" открываются детаилы для каждой строки товара. но при установке курсора ячейку с автоматическим включением редактирование в редактируемом поле отображается значение из другого детаила, который был открыт ранее. И когда начинаю редактировать поле, данные изменяются во всех открытых детаилах в той строке на который был в каждом из них последний раз.