Recently I faced similar problem and didn't find a solution to not write sql manually. So I wrote a little package which allows to write migrations using Ef Core entity builder like this:
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 })));
This code will be translated into sql and applied to migrations will be looks like
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();");
}
}
Maybe it will be helpful for someone.