2013-07-23 2 views
0

Я переношу наше приложение Delphi XE2 из MSSQL (используя компоненты ADO), в PostgreSQL, используя UniDAC.PostgreSQL serial (автоинкремент) с UniDac на Delphi XE2

В базе данных есть поля типа serial (автоинкременты). Когда я добавляю запись, я не помещаю никаких данных в это поле автоинкремента. Формально, с MSSQL/ADO он работает автоматически, но теперь у меня есть исключение.

Код:

aqrMsgs.Append; 
aqrMsgsUser_From.AsInteger := UserId; 
aqrMsgsUser_To.AsString := UserIds[I]; 
aqrMsgsSubject.AsString := Trim (edtSubject.Text); 
aqrMsgsContents.AsString := mmoContents.Text; 
aqrMsgsIsDone.AsBoolean := False; 
aqrMsgs.Post; 

И исключение:

Exception

Поле 'ID' является TIntegerField, не TAutoIncrementField.

Кстати, если я использую возможность редактирования DBGrid (точно, я использую ExpressQuantumGrid), чтобы добавить записи в другую таблицу с одинаковой структурой, все работает нормально.

Как это можно решить? Спасибо.

ответ

1

1) При создании поля с порядковым типом, сервер PostgreSQL автоматически создает последовательность, и значения из этой последовательности будет использоваться по умолчанию для этого поля. Если серийное поле не установлено при вставке новой записи, сервер принимает значение из последовательности для него. Но если вы установите значение для серийного поля, сервер введет это значение. Поскольку последовательность ничего не знает о значении, которое вы вставили в поле серийного номера, то при дальнейшей вставке записей (при использовании последовательности) может возникнуть ошибка «дублирующееся значение ключа», если серийное поле создается с уникальным ограничением , Вы не столкнетесь с этой проблемой, если вручную не задаете значения для этого поля.

2) UniDAC может автоматически заполнять поле, используя последовательность. Для этого вы должны установить TUniQuery.KeyFields и TUniQuery.SpecificOptions.Values ​​[ ''] KeySequence свойства следующим образом:

UniQuery1.KeyFields := 'id'; 
    UniQuery1.SpecificOptions.Values['KeySequence'] := 'test1_id_seq'; 

Кроме того, с помощью TUniQuery.SpecificOptions.Values ​​[ ''] SequenceMode свойство, вы может указать, когда именно UniDAC заполнит поле, используя последовательность: при вызове Append/Insert или Post.

Вы можете найти подробную информацию об указанных свойствах здесь: http://www.devart.com/unidac/docs/pgsqlprov_article.htm

2

Большинство SQL совместимый путь был бы не зачислять это поле в SQL запросе на всех, и пусть он оставил NULL, а затем заполнить его на сервере через SQL Before Insert trigger от null уникальное значение.

Это можно сделать, если UniDAC имеет встроенную настройку запроса запроса, например TUpdateSQL был.

вручную указав INSERT запрос (или INSERT-RETURNING, если вам потребуется идентификатор позже какие-либо причины: http://en.wikipedia.org/wiki/SQL_INSERT) является наиболее управляемым, эффективным и гибким способом для вставки данных.


Однако если вы Append и не хотите писать запросы SQL для делать это, то вы можете прочитать значение идентификатора с сервера, прежде чем делать post.

1) объявить кросс-транзакционный источник ID: SQL SEQUENCE

2) запрос nextval(), прежде чем делать запись и поместить его в поле ID (вы можете сделать это в TDataSet.BeforePost обработчик событий)


Вы также можете прочитать UniDAC документацию и увидеть несколько последовательностей связанных свойств в TUniTable, которые автоматизируют этот процесс для вас. KeySequence и SequenceMode на http://www.devart.com/unidac/docs/pgsqlprov_article.htm#tuniquery_tunitable_tunistoredproc