I am learning ASP.NET Core MVC and my model is
namespace Joukyuu.Models
{
public class Passage
{
public int PassageId { get; set; }
publi
An alternative to using SaveChangesAsync is you can create database triggers for the respective database. I made a gist with some helper functions for mssql, postgress, sqlite, and mysql. Here is a paste of the code.
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace ProjectNamespace.Api.Utils
{
public class DatabaseTools
{
public class DatabaseKeys
{
public string ValueGenerationStrategy;
public object SerialColumn;
public string DEFAULTDATE_CREATE;
public string DEFAULTDATE_UPDATE;
public string dateTime;
public bool UpdateDateTrigger = true;
public string ProviderName { get; set; }
}
/*
Notes:
can check if updateDateTrigger needed for dataprovider and add update triggers
if (dbKeys.UpdateDateTrigger)
{
migrationBuilder.Sql(DatabaseTools.getUpdateDateTrigger(dbKeys.ProviderName, "TG_roles_updated_at", "roles", "updated_at"));
}
if postgress don't forget to drop the generated functions for each of the different named update columns (updated_at, modified_date) at the end of the migration E.g.
protected override void Down(MigrationBuilder migrationBuilder){...
if (dbKeys.ProviderName == "postgress")
{
migrationBuilder.Sql(@"
DROP FUNCTION update_" + "updated_at" + @"_column();
");
}
postgres doesn't support parameters in triggers for new and old keywords.
*/
///
/// needed for non mysql implementation to update a datetime on a record update
///
///
///
///
///
///
///
///
public static string getUpdateDateTrigger(string databaseProvider, string name, string table, string column, string schema = "", string id_column = "id")
{
string updateDateTrigger = null;
if (!string.IsNullOrEmpty(schema))
schema = schema + ".";
switch (databaseProvider)
{
case "sqlite":
updateDateTrigger = @"
CREATE TRIGGER [" + name + @"]
AFTER
UPDATE
ON " + table + @"
FOR EACH ROW
WHEN NEW." + column + @" <= OLD." + column + @"
BEGIN
update " + table + @" set " + column + @"=CURRENT_TIMESTAMP where " + id_column + @"=OLD." + id_column + @";
END
";
break;
case "postgress":
updateDateTrigger = @"
CREATE OR REPLACE FUNCTION update_" + column + @"_column() RETURNS TRIGGER AS
$$
BEGIN
NEW.""" + column + @""" = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER " + name + @"
BEFORE UPDATE ON " + schema + @"""" + table + @"""
FOR EACH ROW EXECUTE PROCEDURE update_" + column + @"_column();
";
break;
case "sqlserver":
updateDateTrigger = @"
CREATE TRIGGER " + name + @"
ON " + table + @"
AFTER UPDATE AS
UPDATE " + table + @"
SET " + column + @" = GETDATE()
WHERE " + id_column + @" IN (SELECT DISTINCT " + id_column + @" FROM Inserted);
";
break;
}
return updateDateTrigger;
}
/*
Notes:
if in OnModelCreating can call as var dbKeys = DatabaseTools.getDatabaseDefaults(this.Database.ProviderName);
if in a migration call as var dbKeys = DatabaseTools.getDatabaseDefaults(migrationBuilder.ActiveProvider);
Then update any datetime columns for correct defaults
created_at = table.Column(type: dbKeys.dateTime, nullable: true, defaultValueSql: dbKeys.DEFAULTDATE_CREATE),
updated_at = table.Column(type: dbKeys.dateTime, nullable: true, defaultValueSql: dbKeys.DEFAULTDATE_UPDATE)
*/
///
/// Can get specific formats for different databases. Supports mssql, postgress, sqlite, and mysql.
///
///
///
public static DatabaseKeys getDatabaseDefaults(string databaseProvider)
{
var dbKeys = new DatabaseKeys();
dbKeys.dateTime = "datetime";
switch (databaseProvider)
{
case "Microsoft.EntityFrameworkCore.Sqlite":
case "sqlite":
dbKeys.DEFAULTDATE_UPDATE = "datetime('now')";
dbKeys.SerialColumn = true;
dbKeys.ProviderName = "sqlite";
dbKeys.ValueGenerationStrategy = "Sqlite:Autoincrement";
break;
case "postgress":
case "Npgsql.EntityFrameworkCore.PostgreSQL":
dbKeys.DEFAULTDATE_UPDATE = "CURRENT_TIMESTAMP";
dbKeys.SerialColumn = NpgsqlValueGenerationStrategy.SerialColumn;
dbKeys.ProviderName = "postgress";
dbKeys.ValueGenerationStrategy = "Npgsql:ValueGenerationStrategy";
dbKeys.dateTime = "timestamp";
break;
case "mysql":
case "MySql.Data.EntityFrameworkCore":
dbKeys.DEFAULTDATE_UPDATE = "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP";
dbKeys.DEFAULTDATE_CREATE = "CURRENT_TIMESTAMP";
dbKeys.UpdateDateTrigger = false;
dbKeys.SerialColumn = true;
dbKeys.ProviderName = "mysql";
dbKeys.ValueGenerationStrategy = "MySQL:AutoIncrement";
break;
case "sqlserver":
default:
dbKeys.DEFAULTDATE_UPDATE = "(getdate())";
dbKeys.SerialColumn = SqlServerValueGenerationStrategy.IdentityColumn;
dbKeys.ProviderName = "sqlserver";
dbKeys.ValueGenerationStrategy = "SqlServer:ValueGenerationStrategy";
break;
}
if (string.IsNullOrEmpty(dbKeys.DEFAULTDATE_CREATE))
dbKeys.DEFAULTDATE_CREATE = dbKeys.DEFAULTDATE_UPDATE;
return dbKeys;
}
}
}