SQL Server触发器和sqlalchemy干扰问题。需要帮助

时间:2011-01-25 10:23:40

标签: sql sql-server triggers sqlalchemy

我需要对某些关键表进行一种“版本控制”,并试图以一种相当简单的方式实现它:

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 个答案:

答案 0 :(得分:4)

您应该将'implicit_returning'设置为'False',以避免在SQLAlchemy生成的查询中使用“OUTPUT”(这应解决您的问题):

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 :(得分:1)

我似乎无法添加评论,因此添加了另一个答案。

这并不复杂,我建议它不如在您的域中放置1/2业务逻辑而在数据库触发器中放置另一半更不易碎。

就个人而言,我会编写自己的列表对象,并引用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之前会自动更新,而另一位查看代码的开发人员可以很容易地看到您所做的事情。

答案 2 :(得分:0)

这不会直接回答你的问题,但根据我使用触发器的经验会导致无尽的痛苦,所以不惜一切代价避免它们。如果您自己管理所有数据,那么简单的答案就是自己填充版本历史记录表。这也意味着您将所有业务逻辑集中在一个地方,这是一个奖励!