2013-12-04 2 views
8

Мы используем PetaPoco в качестве нашего инструмента для доступа к данным для базы данных SQL 2008. У нас возникла проблема при попытке вставить/обновить строку в таблице, в которой есть триггер.Вставка PetaPoco сбоя на стол с триггером

Мы используем db.Save (объект) PetaPoco;

Показанная ошибка: Таблица целей 'the_table_with_a_trigger' оператора DML не может иметь активированных триггеров, если оператор содержит предложение OUTPUT без предложения INTO.

Как мы можем использовать PetaPoco для вставки/обновления данных в таблице с триггером?

+0

Как вы думаете, вам нужно будет иметь эту БД и/или ваш код, чтобы помочь вам? –

+0

Я так не думаю. По всей видимости, это проблема внутри PetaPoco в отношении таблиц с триггерами. Я предполагаю, что способ, которым PetaPoco создает команды вставки, конфликтует с триггерами. Я надеюсь, что кто-то с опытом PetaPoco может объяснить исправление или обходное решение. –

ответ

6

Благодаря @Eduardo Molteni, вы меня на правильный путь к решению этого. По-видимому, в SQL Server 2008 R2 известно, что команда OUTPUT в вставке не будет работать, если в таблице есть триггер. Тем не менее, PetaPoco автоматически вставляет предложение OUTPUT в текст команды любой вставки, где таблица имеет AutoIncrement = true.

Раствор для меня (для SQL Server 2008 R2) заключается в следующем:

1) Перейти к функции PetaPoco.DatabaseTypes.SqlServerDatabaseType.GetInsertOutputClause

удалить (закомментировать) \\return String.Format(" OUTPUT INSERTED.[{0}]", primaryKeyName);

Это удаляет «OUTPUT» из инструкции SQL insert. Теперь вставка произойдет в таблице с триггером. Однако теперь у PetaPoco нет способа получить новый первичный ключ (идентификатор) из недавно вставленной строки.

2) Перейти к функции PetaPoco.Database.Insert. Непосредственно над линией:

object id = _dbType.ExecuteInsert(this, cmd, primaryKeyName); 

добавить новую строку, поэтому она выглядит следующим образом:

cmd.CommandText += ";\nSELECT SCOPE_IDENTITY() AS NewID;"; 
object id = _dbType.ExecuteInsert(this, cmd, primaryKeyName); 

Новая линия (которая существовала в PetaPoco, но не используется) позволит вставку чтобы получить идентификатор.

1

PetaPoco создает только параметр OUTPUT в Oracle DB для получения нового идентификатора AutoIncrement.

В случае сервера Sql, когда вы отметили свой вопрос, он добавляет только SELECT SCOPE_IDENTITY() AS NewID, если таблица имеет идентификатор автоинкремента.

Соответствующий код в PetaPoco.cs:

cmd.CommandText = string.Format("INSERT INTO {0} ({1}) VALUES ({2})", 
     EscapeTableName(tableName), 
     string.Join(",", names.ToArray()), 
     string.Join(",", values.ToArray()) 
     ); 

if (!autoIncrement) { 
    DoPreExecute(cmd); 
    cmd.ExecuteNonQuery(); 
    OnExecutedCommand(cmd); 
    return true; 
} 

object id; 
switch (_dbType) { 
    case DBType.SqlServer: 
     cmd.CommandText += ";\nSELECT SCOPE_IDENTITY() AS NewID;"; 
     DoPreExecute(cmd); 
     id = cmd.ExecuteScalar(); 
     OnExecutedCommand(cmd); 
     break; 

Попробуйте отключив AutoIncrement ID и установить его вручную, чтобы увидеть, если проблема исчезнет

2

Думаю, cmd.CommandText += ";\nSELECT SCOPE_IDENTITY() AS NewID;"; будет лучше. @@ IDENTITY может дать вам идентификатор, сгенерированный в триггере, а не ваш оператор.

1

Потому что я уверен, что я не буду последним человеком, который встречает это ...

Я принял PetaPoco для нового проекта, но я столкнулся с подобной проблемой, но возвращаясь к scope_identity() не собирался работать. Таким образом, я:

1) Увеличенный интерфейс IProvider.

/// <summary> 
    ///  Return an SQL expression that can be used with <seealso cref="GetInsertPostScript(string)"/> 
    ///  and <seealso cref="GetInsertOutputClause(string)"/> to return a provider-generated value from an INSERT; typically an IDENTITY 
    ///  column in Microsoft SQL Server. 
    /// </summary> 
    /// <param name="primaryKeyName"></param> 
    /// <returns></returns> 
    string GetInsertPreamble(string primaryKeyName); 

    /// <summary> 
    ///  Return an SQL expression that can be used with <seealso cref="GetInsertPreamble(string)"/> 
    ///  and <seealso cref="GetInsertOutputClause(string)"/> to return a provider-generated value from an INSERT; typically an IDENTITY 
    ///  column in Microsoft SQL Server. 
    /// </summary> 
    /// <param name="primaryKeyName"></param> 
    /// <returns></returns> 
    string GetInsertPostScript(string primaryKeyName); 

2) Добавлен их DatabaseProvider.cs:

public virtual string GetInsertPreamble(string primaryKeyName) 
    { 
     return string.Empty; 
    } 

    public virtual string GetInsertPostScript(string primaryKeyName) 
    { 
     return string.Empty; 
    } 

3) Затем SqlServerDatabaseProvider, включая изменение существующего пункт OUTPUT:

public override string GetInsertOutputClause(string primaryKeyName) 
    { 
     return String.Format(" OUTPUT INSERTED.[{0}] into @result({0})", primaryKeyName); 
    } 

    public override string GetInsertPreamble(string primaryKeyName) 
    { 
     return string.Format("DECLARE @result TABLE({0} sql_variant); ", primaryKeyName); 
    } 

    public override string GetInsertPostScript(string primaryKeyName) 
    { 
     return string.Format("; SELECT {0} FROM @result; ", primaryKeyName); 
    } 

4) И, наконец, включили их в базу данных .cs: ​​

    ...string outputClause = string.Empty; 
        string insertPreamble = string.Empty; 
        string insertPostScript = string.Empty; 
        if (autoIncrement) 
        { 
         insertPreamble = _provider.GetInsertPreamble(primaryKeyName, tableName); 
         outputClause = _provider.GetInsertOutputClause(primaryKeyName); 
         insertPostScript = _provider.GetInsertPostScript(primaryKeyName, tableName); 
        } 

        cmd.CommandText = string.Concat(
         $"{insertPreamble}", 
         $"INSERT INTO {_provider.EscapeTableName(tableName)} ({(string.Join(",", names.ToArray()))})", 
         $"{outputClause}", 
         $" VALUES ({(string.Join(",", values.ToArray()))})", 
         $"{insertPostScript}" 
        ) ; 

        if (!autoIncrement) 
        {.... 

Это изменяет команду на использование именованной переменной TABLE, DECLAREd в «Preamble», заполненной предложением OUTPUT и SELECTed в «PostScript».

Смежные вопросы