Текущий архив: 2008.05.18;
Скачать: CL | DM;
ВнизОшибка "некоторые записи могли быть изменены" Найти похожие ветки
← →
SuperNick (2007-12-13 12:33) [0]Здравствуйте!
Есть программа на Дельфи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 корректны.
Что можно попробовать? Может быть, проблема еще в том, что запись добавляется в подчиненную таблицу в первый раз, первичного ключа, на который можно было бы ориентироваться еще нет (при операции редактирования существующей записи все работает).
← →
ЮЮ © (2007-12-13 12:57) [1]Похоже, в таком случае запись не INSERT-ится, а UPDATE-тся (ведь она в НД есть из-за левой части), а в таблице её не, отсюда и "некоторые записи могли быть изменены", т.е. запись вроде была а UPDATE не изменяет ни одной записи.
> Что можно попробовать?
Обой-ти "умную" АDO. Искать место в механизме, где можно послать иной запрос на сервер.
← →
Anatoly Podgoretsky © (2007-12-13 13:07) [2]Оно так и есть, данные будут изменены, тем же пользователем. Откажись от DbGrid и проблемм не будет.
← →
Sergey13 © (2007-12-13 13:13) [3]> [0] SuperNick (13.12.07 12:33)
ИМХО сами создаем себе трудности и сами мужественно их преодолеваем.
Искусственное разбиение на 2 таблицы уже дает нормальные результаты.
← →
Slym © (2007-12-14 13:43) [4]Значения по умолчанию в базе убери
← →
sniknik © (2007-12-14 17:13) [5]ЮЮ © (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]) когда необходимо, и если ничего больше из "пузырьков" не вылезет, должно работать.
← →
sniknik © (2007-12-14 17:46) [6]вот, накидал пример, вполне рабочий, остались конечно неувязочки... но даже думать на эту тему неохота. (и так все изза идиотского проектирования)
в общем, при добавлении записи (пост в гриде по стрелке вниз, вверх) курсор остается на месте, надо жать 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.
и dfmobject 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
Страницы: 1 вся ветка
Текущий архив: 2008.05.18;
Скачать: CL | DM;
Память: 0.49 MB
Время: 0.047 c