Триггеры SQL Server и проблема вмешательства sqlalchemy.Нужна помощь - PullRequest
3 голосов
/ 25 января 2011

Мне нужно что-то вроде «контроля версий» для некоторых критических таблиц, и я попытался реализовать это довольно простым способом:

CREATE TABLE [dbo].[Address] (
  [id] bigint IDENTITY(1, 1) NOT NULL,
  [post_code] bigint NULL,
...
)

CREATE TABLE [dbo].[Address_History] (
  [id] bigint NOT NULL,
  [id_revision] bigint NOT NULL,
  [post_code] bigint NULL,
...
  CONSTRAINT [PK_Address_History] PRIMARY KEY CLUSTERED ([id], [id_revision]),
  CONSTRAINT [FK_Address_History_Address]...
  CONSTRAINT [FK_Address_History_Revision]...
)

CREATE TABLE [dbo].[Revision] (
  [id] bigint IDENTITY(1, 1) NOT NULL,
  [id_revision_operation] bigint NULL,
  [id_document_info] bigint NULL,
  [description] varchar(255) COLLATE Cyrillic_General_CI_AS NULL,
  [date_revision] datetime NULL,
...
)

и куча триггеров на вставку / обновление / удаление для каждой таблицы, которая предназначена для хранения ее изменений.

Мое приложение основано на PyQt + sqlalchemy, и когда я пытаюсь вставить сущность, которая хранится в версионной таблице, sqlalchemy выдает ошибку:

The target table 'Heritage' of the DML statement cannot have 
any enabled triggers if the statement contains 
an OUTPUT clause without INTO clause. 
(334) (SQLExecDirectW); [42000] 
[Microsoft][ODBC SQL Server Driver]
[SQL Server]Statement(s) could not be prepared. (8180)")

Что мне делать? Я должен использовать sqlalchemy. Если кто-то может дать мне совет, как я могу реализовать управление версиями без триггеров, это было бы круто.

Ответы [ 3 ]

4 голосов
/ 05 ноября 2015

Вы должны установить 'implicit_returning' в 'False', чтобы избежать использования "OUTPUT" в запросе, созданном SQLAlchemy (и это должно решить вашу проблему):

class Company(sqla.Model):
    __bind_key__ = 'dbnamere'
    __tablename__ = 'tblnamehere'
    __table_args__ = {'implicit_returning': False}  # http://docs.sqlalchemy.org/en/latest/dialects/mssql.html#triggers
    id = sqla.Column('ncompany_id', sqla.Integer, primary_key=True)
    ...
1 голос
/ 09 февраля 2011

Кажется, я не могу добавить комментарий, поэтому добавляю еще один ответ.

Это не так сложно, и я бы посоветовал, что это менее хрупко, чем поместить половину вашей бизнес-логики в ваш домен и другую половину в вашу базу данных.спусковой крючок.

Лично я бы написал свой собственный объект списка со ссылкой на список истории для some_list_of_other_entities и в методах Remove и Add, чтобы сохранить записи истории.

Таким образом, ваши объекты автоматически обновляются допрежде чем даже сохранять их в своем ORM.

public class ListOfOtherEntities : System.Collections.IEnumerable
{
    // Add list stuff here...

    public void Remove(MyEntity obj)
    {
        this.List.Remove(obj);
        this.History.Add(new History("Added a object!");
    }

    public void Remove(MyEntity obj)
    {
        this.List.Remove(obj);
        this.History.Add(new History("Removed a object!");
    }
}

Таким образом, ваши объекты автоматически обновляются, прежде чем даже сохранять их в своем ORM, и другой разработчик, глядя на код, может легко увидеть, что вы сделали.

0 голосов
/ 04 февраля 2011

Это не ответит на ваш вопрос напрямую, но по моему опыту использование триггеров приводит к бесконечной боли, поэтому избегайте их любой ценой.Если вы сами управляете всеми данными, простой ответ - заполнить таблицы истории версий самостоятельно.Это также означает, что у вас есть вся ваша бизнес-логика в одном месте, что является бонусом!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...