【问题标题】:Add database trigger with Entity Framework Code First Migrations使用 Entity Framework Code First 迁移添加数据库触发器
【发布时间】:2014-02-12 15:17:21
【问题描述】:

我首先使用实体​​框架迁移代码来控制我的数据库模型。它很迷人,我可以处理到现在所有的事情。但是现在我需要添加一个数据库触发器,并且我想使用 EF 迁移来执行此操作,而不是仅针对这种情况使用单独的 sql 脚本(这会让客户感到困惑,尤其是在我们说服他们我们可以处理所有事情之后) EF 迁移)。 我的触发器是直截了当的,看起来像 tis:

CREATE OR REPLACE TRIGGER [name] BEFORE UPDATE ON myTable ...

是否有向 EF 迁移添加触发器的命令?

【问题讨论】:

  • 查看我提出的解决方案:EntityFramework.Triggers。它也在 NuGet 上。
  • 看起来很有希望。你知道吗,它是否支持多个数据库系统(oracle、sql server 等)
  • 我只使用 SQL Server 对其进行了测试,但它都以与提供程序无关的方式构建在实体框架之上。这取决于DbContext

标签: .net entity-framework entity-framework-migrations


【解决方案1】:

您只需将Sql("SQL COMMAND HERE") 方法调用添加到迁移的Up 方法即可。不要忘记将 drop 语句也添加到 Down 方法中。如果需要,您可以创建一个空迁移,只需运行 Add-Migration 而无需对模型进行任何更改。

public partial class Example : DbMigration
{
    public override void Up()
    {
        Sql("CREATE OR REPLACE TRIGGER [name] BEFORE UPDATE ON myTable ...");
    }

    public override void Down()
    {
        Sql("DROP TRIGGER [name]");
    }
}

【讨论】:

  • 你也可以将 IF NOT EXISTS(select * from sys.triggers where name = 'name') 添加到 UP() 使其具有幂等性。
  • @eoghank。我不确定我是否同意。迁移的想法是它们应该在所有方向上都是可重复的,因此它们可以防止这种情况发生。从理论上讲,如果我们需要存在性检查,我们就没有正确使用迁移——因为我们不对表进行存在性检查,所以我们不应该对触发器进行检查?
  • 对于 EF 核心,使用 migrationBuilder.Sql("blah blah...");
  • 如果编写这样的迁移(对于 ef、ef core 或 fluent 迁移器)我不能使用“向下”部分。示例:第一次迁移创建触发器。第二次迁移更新触发器。我迁移数据库。很好..第二次迁移没有失败,因为它取代了第一次迁移的触发器,但是现在..我想降级一步。 UPS!从技术上讲,我在迁移 1 中,但没有触发器 bcs,它已被迁移 2 的 Down 步骤删除。
  • @korulis,第二次迁移是更新,所以它的“Down”应该更新到原始状态(而不是丢弃)
【解决方案2】:

最近我遇到了类似的问题,没有找到不手动编写sql的解决方案。所以我写了一点package,它允许使用 Ef Core 实体构建器编写迁移,如下所示:

modelBuilder.Entity<Transaction>()
    .AfterInsert(trigger => trigger
        .Action(triggerAction => triggerAction
            .Upsert(transaction => new { transaction.UserId },
                insertedTransaction => new UserBalance { UserId = transaction.UserId, Balance = insertedTransaction.Sum },
                (insertedTransaction, oldBalance) => new UserBalance { Balance = oldBalance.Balance + insertedTransaction.Sum })));

此代码将被翻译成 sql 并应用于迁移将如下所示

public partial class AddTriggers : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql("CREATE FUNCTION LC_TRIGGER_AFTER_INSERT_TRANSACTION() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_TRANSACTION$ BEGIN INSERT INTO user_balances (user_id, balance) VALUES (NEW.user_id, NEW.sum) ON CONFLICT (user_id) DO UPDATE SET balance = user_balances.balance + NEW.sum; RETURN NEW;END;$LC_TRIGGER_AFTER_INSERT_TRANSACTION$ LANGUAGE plpgsql;CREATE TRIGGER LC_TRIGGER_AFTER_INSERT_TRANSACTION AFTER INSERT ON transactions FOR EACH ROW EXECUTE PROCEDURE LC_TRIGGER_AFTER_INSERT_TRANSACTION();");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql("DROP TRIGGER LC_TRIGGER_AFTER_INSERT_TRANSACTION ON transactions;DROP FUNCTION LC_TRIGGER_AFTER_INSERT_TRANSACTION();");
    }
}

也许它会对某人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 1970-01-01
    • 2020-08-10
    • 2014-05-08
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    相关资源
    最近更新 更多