实体框架6 / SQL Server触发器 - 出现错误

6
我有一个EF6解决方案,我想在表上添加触发器以将更改记录到新表中。这是由于我们正在与外部数据库进行集成。基本上,他们希望有一个更改日志用于同步目的。
当我通过SSMS(Azure SQL DB)执行时,触发器完美地工作,但是当我通过我们的Web应用程序进行测试时,我会收到以下错误:
(0x80131904):如果语句包含没有INTO子句的OUTPUT子句,则DML语句的目标表'DestinationTable'不能具有任何启用的触发器。
基本上看起来我无法为使用Entity Framework的表分配触发器。
有人有任何想法如何使其正常工作吗?
提前感谢。

错误实际上告诉您,如果没有INTO从句,就不能使用OUTPUT,而不是“您不能在Entity Framework中使用触发器”。错误告诉您问题所在;如果有一个OUTPUT,它也需要有一个INTO从句。 - Thom A
只有在通过EF执行操作时才会触发错误。因此,我猜测由EF生成的底层SQL使用了没有INTO的OUTPUT。您知道是否有一种方法可以修改EF过程以符合要求吗? - Shawn Dillon
你确定这是启用了批处理的EF6而不是EF Core吗?据我所知,EF6不使用OUTPUT。 - David Browne - Microsoft
EF6和EF Core版本6之间的区别?嗯,这真的很令人困惑。我想我现在遇到了这个问题。我有一个叫做ef core和6.0.21的东西...那是ef6还是其他什么?无论如何,触发器的功能仍然存在问题,并且在6.0.21中,.Conventions无法编译。 - PHenry
4个回答

9

使用EF Core 7.X时遇到了相同的错误。

我在一个表上有一个触发器,插入时返回错误。

The target table 'MyTable' of the DML statement cannot have any enabled 
triggers if the statement contains an OUTPUT clause without INTO clause

如果我去掉了触发器的逻辑,仍然会收到错误。禁用触发器解决了这个错误。但是,如果我执行手动插入操作,则在SSMS中不会返回任何错误。

对于我来说,解决方案是(让DBContext实体对象知道该表上有一个触发器)。

更新Fluent API为...

builder.Entity<MyTable>(entry =>
    {
       entry.ToTable("MyTable", tb => tb.HasTrigger("MyTable_Insert"));
    });

关于这个主题的更多信息可以在微软网站上找到,有关EF Core 7.0 (EF7)中的重大变化,请参阅EF Core 7.0 (EF7)中的重大变化


1
如果表格有多个触发器会怎样? - blane
builder.Entity<MyTable>(entry => { entry.ToTable("MyTable", tb => { tb.HasTrigger("MyTable_Insert"); tb.HasTrigger("MyTable_Update"); }); }); - BDarley
1
一个 HasTrigger 语句就足够了。它只是告诉 EF 表格有触发器,甚至触发器的名称都不重要。 - Gert Arnold

4

我的问题类似 - 也涉及到 EF Core 7.X 中的一个重大变化,但我选择了另一种替代方案,这个方案在文档中也有提到,因为我的所有表都有触发器...

Microsoft文档所述,在缓解措施部分,以下内容应该有所帮助:

If most or all of your tables have triggers, you can opt out of using the newer, efficient technique for all your model's tables by using the following model building convention:

public class BlankTriggerAddingConvention : IModelFinalizingConvention
{
    public virtual void ProcessModelFinalizing(
        IConventionModelBuilder modelBuilder,
        IConventionContext<IConventionModelBuilder> context)
    {
        foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
        {
            var table = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table);
            if (table != null
                && entityType.GetDeclaredTriggers().All(t => t.GetDatabaseName(table.Value) == null))
            {
                entityType.Builder.HasTrigger(table.Value.Name + "_Trigger");
            }

            foreach (var fragment in entityType.GetMappingFragments(StoreObjectType.Table))
            {
                if (entityType.GetDeclaredTriggers().All(t => t.GetDatabaseName(fragment.StoreObject) == null))
                {
                    entityType.Builder.HasTrigger(fragment.StoreObject.Name + "_Trigger");
                }
            }
        }
    }
}

Use the convention on your DbContext by overriding ConfigureConventions:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Conventions.Add(_ => new BlankTriggerAddingConvention());
}

请查看此元帖。我认为最好在评论中提到这一点。 - Gert Arnold
1
嘿,Gert,谢谢。我根据你的链接答案更新了答案。我认为这对于评论来说有点冗长,特别是在代码格式化方面。最重要的是,这是一个针对手头问题的样板答案,我在SO上没有直接找到! - Duck Ling

1
我已经找到了问题所在,与我们使用的名为ZEntity.BulkOperations.Extension的扩展包有关。David Browne的评论使我记录了错误,并且内部异常指向ZEntity BulkInsert作为错误。然后我发现了这个链接https://github.com/zzzprojects/EntityFramework-Extensions/issues/334,指出这个包确实处理触发器。我只需要停止并重新启动使用db和该包的服务,以便ZEntity可以发现新添加的触发器。

简而言之,我只需停止并重新启动服务,使ZEntity包意识到新添加的触发器即可。

感谢所有回答者!


1

这是一个比较少见的问题,但我发现自己遇到了这个错误,使用的是Microsoft.EntityFrameworkCore.SqlServer 7.0.0-preview。

当我回退到6.0.8版本时,错误消失了。

这就是开发预览版的风险所在。


4
这在最新的稳定版7.0.0中仍然存在-我降级到了6.0.11,错误消失了。我们的触发器根本没有OUTPUT子句。 - lukep
哇,@lukep 谢谢你提醒。我想我会再等一会儿。 - Wellspring
啊,糟糕。我降级到了6.0.21版本,试图摆脱这个错误,但它仍然影响着我。: < 真是令人沮丧。 - PHenry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接