Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ошибка "некоторые записи могли быть изменены" [D7, access]


SuperNick ©   (2007-12-13 12:33:00) 

Здравствуйте!
Есть программа на Дельфи7, БД на Access, связь по ADO.  Я приведу фрагмент для примера. В БД существуют 2 таблицы, фактически их можно свести в одну, но в силу требований к программе и БД (таблицы будут заполняться в разное время и разными людьми), чтобы никто не мог испортить чужие данные (или более важные данные), таблиц реализовано 2 штуки.

Table1 (точки):
Id_point (счетчик, PK)
Name_point
Параметр

Table2 (напряжение в точках):
Id_point (FK на Table1)
Напряжение 1
….
Две таблички можно свести в одну и разными способами показывать пользователю те или другие столбцы для заполнения. По постановке - отпадает. Для надежности – разделение на 2 таблицы в БД. В итоге – связь между Table1 и Table2 – “один-к-одному”.
А вот пользователю для редактирования таблицы требуется представить в виде одной (вывести ее в DBGrid). Реализовано с помощью AdoQuery и запроса на объединение Left outer join (при этом записи, для которых не заданы значения в Table2 также выводятся, можно ввести значения). В принципе, все хорошо, но вот проблема, связанная с ADO, а именно: при попытке добавить запись в Table2 - сообщение "Некотороые значения могли быть изменены со времени последнего чтения". При этом выполнены все советы, что знал сам и прочитал про ADO:
- родительская запись в Table1 присутствует;
- уникальные первичные ключи есть во всех таблицах;
- TADODataSet(DataSet).Properties['Unique Table'].Value:=<имя Table 2> присутствует;
- TADODataSet(DataSet).Properties['Update Resync'].Value:=15{adResyncAll} присутствует;
- TADODataSet(DataSet).Properties['Update Criteria'].Value:=0{adCriteriaKey} присутствует;
- TADODataSet(DataSet).Properties['Resync Command'].Value:='select ...' - как описано в статьях об использовании ADO в Дельфи - присутствует;
- Настройки самой ADOQuery и ADOConnection корректны.
Что можно попробовать? Может быть, проблема еще в том, что запись добавляется в подчиненную таблицу в первый раз, первичного ключа, на который можно было бы ориентироваться еще нет (при операции редактирования существующей записи все работает).


sniknik   (2007-12-14 17:46:00) [1]

вот, накидал пример, вполне рабочий, остались конечно неувязочки... но даже думать на эту тему неохота. (и так все изза идиотского проектирования)
в общем, при добавлении записи (пост в гриде по стрелке вниз, вверх) курсор остается на месте, надо жать 2 раза, не так как при редактировании.
ну и невозможность добавлять записи в первую (основную) таблицу, т.к. чтобы получить автоинкремент нужно запостить запись, а мы этого не можем т.к. нет значения для второй таблицы. замкнутый круг однако... (решить конечно можно, еще одной вариацией запроса для этого случая, но нафик)

код
unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, Grids, DBGrids, DB, ADODB, ADOInt;

type
 TForm1 = class(TForm)
   ADOConnection1: TADOConnection;
   ADODataSet1: TADODataSet;
   DataSource1: TDataSource;
   DBGrid1: TDBGrid;
   ADOCommand1: TADOCommand;
   procedure FormCreate(Sender: TObject);
   procedure ADODataSet1AfterOpen(DataSet: TDataSet);
   procedure ADODataSet1BeforePost(DataSet: TDataSet);
 private
 public
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 //предварительно создать таблицы в базе ttt.mdb (или исправить коннект и т.д)
 //CREATE TABLE LTable (ID INT Identity(1, 1) PRIMARY KEY, Name VarChar(50))
 //CREATE TABLE RTable (ID INT PRIMARY KEY, Name VarChar(50))

 ADODataSet1.Open;
 ADODataSet1.FieldByName('r.ID').Visible:= false;
end;

procedure TForm1.ADODataSet1AfterOpen(DataSet: TDataSet);
begin
 with TADODataSet(DataSet) do begin
   Properties['Update Criteria'].Value:= adCriteriaKey;
   Properties['Unique Table'   ].Value:= 'LTable';
   Properties['Resync Command' ].Value:=
     'SELECT * FROM LTable l LEFT JOIN RTable r ON l.ID=r.ID WHERE l.ID=?';
 end;
end;

procedure TForm1.ADODataSet1BeforePost(DataSet: TDataSet);
begin
 with TADODataSet(DataSet) do
   if FieldByName('r.ID').IsNull then begin
     ADOCommand1.Parameters.ParamByName('ID'  ).Value:= FieldByName('l.ID'  ).AsInteger;
     ADOCommand1.Parameters.ParamByName('Name').Value:= FieldByName('r.Name').AsString;
     ADOCommand1.Execute;

     Cancel;
     Recordset.Resync(adAffectCurrent, adResyncAllValues);
     Resync([rmExact]);

     Abort;
   end;
end;

end.


и dfm
object Form1: TForm1
 Left = 251
 Top = 107
 Width = 747
 Height = 549
 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 DBGrid1: TDBGrid
   Left = 24
   Top = 80
   Width = 673
   Height = 369
   DataSource = DataSource1
   TabOrder = 0
   TitleFont.Charset = DEFAULT_CHARSET
   TitleFont.Color = clWindowText
   TitleFont.Height = -11
   TitleFont.Name = 'MS Sans Serif'
   TitleFont.Style = []
 end
 object ADOConnection1: TADOConnection
   ConnectionString =
     'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=ttt.mdb;Persist Sec' +
     'urity Info=False'
   LoginPrompt = False
   Mode = cmShareDenyNone
   Provider = 'Microsoft.Jet.OLEDB.4.0'
   Left = 48
   Top = 16
 end
 object ADODataSet1: TADODataSet
   Connection = ADOConnection1
   CursorType = ctStatic
   AfterOpen = ADODataSet1AfterOpen
   BeforePost = ADODataSet1BeforePost
   CommandText = 'SELECT * FROM LTable l LEFT JOIN RTable r ON l.ID=r.ID '
   Parameters = <>
   Left = 104
   Top = 16
 end
 object DataSource1: TDataSource
   DataSet = ADODataSet1
   Left = 160
   Top = 16
 end
 object ADOCommand1: TADOCommand
   CommandText = 'INSERT INTO RTable (ID,Name) VALUES (:ID,:Name)'
   Connection = ADOConnection1
   Parameters = <
     item
       Name = 'ID'
       Attributes = [paNullable]
       DataType = ftWideString
       NumericScale = 255
       Precision = 255
       Size = 510
       Value = '0'
     end
     item
       Name = 'Name'
       Attributes = [paNullable]
       DataType = ftString
       Size = 50
       Value = ''''''
     end>
   Left = 224
   Top = 16
 end
end


sniknik   (2007-12-14 17:13:00) [2]

ЮЮ ©   (13.12.07 12:57) [1]
> Искать место в механизме, где можно послать иной запрос на сервер.
чего его искать? "бефорепост" однозначно.

Slym ©   (14.12.07 13:43) [4]
> Значения по умолчанию в базе убери
именно здесь, это не причем. при других условиях возможно...

> - Настройки самой ADOQuery и ADOConnection корректны.
вот это меня всегда умиляет... хот и не работает, но неважно, все одно полная уверенность "я все правильно сделал! а виноват в "неработе" ктото другой. естественно."

у тебя даже в показанном мизере есть ошибка, а уж сколько их в "волшебных пузырьках"...  (точки и умолчания имеются ввиду), только догадываться.
ошибка
> - TADODataSet(DataSet).Properties['Unique Table'].Value:=< имя Table 2> присутствует;
а должно бы присутствовать "имя Table 1" т.к. у тебя связь сам пишешь второй таблице к первой, и во второй есть пропуски, т.е. первая более полная, всегда имеет ключевое поле по которому можно обновить всю связку, а вот вторая в части полей имеет null в тех местах где нет совпадений, а по null  какие могут быть операции?

в общем исправить это, плюс заменить апдейт на инсерт (см. [1]) когда необходимо, и если ничего больше из "пузырьков" не вылезет, должно работать.


Slym   (2007-12-14 13:43:00) [3]

Значения по умолчанию в базе убери


Sergey13   (2007-12-13 13:13:00) [4]

> [0] SuperNick   (13.12.07 12:33)
ИМХО сами создаем себе трудности и сами мужественно их преодолеваем.
Искусственное разбиение на 2 таблицы уже дает нормальные результаты.


Anatoly Podgoretsky   (2007-12-13 13:07:00) [5]

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


ЮЮ   (2007-12-13 12:57:00) [6]

Похоже, в таком случае запись не INSERT-ится, а UPDATE-тся (ведь она в НД есть из-за левой части), а в таблице её не, отсюда и "некоторые записи могли быть изменены", т.е. запись вроде была а UPDATE не изменяет ни одной записи.

> Что можно попробовать?

Обой-ти "умную" АDO. Искать место в механизме, где можно послать иной запрос на сервер.


Наверх

Титульная страница Поиск, карта сайта Написать письмо