我正在学习ASP.NET Core MVC,我的模型是
namespace Joukyuu.Models
{
public class Passage
{
public int PassageId { get; set; }
public string Contents { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime ModifiedDate { get; set; }
}
}
Passage
表用于保存我写的段落。
Create
视图只有一个字段Contents
来输入一个段落。服务器必须自动将CreatedDate
和ModifiedDate
设置为相等(使用UTC格式)。
Edit
视图只有一个字段Contents
来编辑一个段落。 ModifiedDate
必须由服务器自动设置。
我需要将哪些属性附加到CreatedDate
和ModifiedDate
属性,以便服务器根据上述方案自动填充这些属性?
答案 0 :(得分:19)
我必须将哪些属性附加到CreatedDate和ModifiedDate属性,以使服务器根据上述方案自动填充这些属性?
解决方案1)
namespace Joukyuu.Models
{
public class Passage
{
public int PassageId { get; set; }
public string Contents { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime ModifiedDate { get; set; }
public Passage()
{
this.CreatedDate = DateTime.UtcNow;
this.ModifiedDate = DateTime.UtcNow;
}
}
}
通过编辑,你必须自己更改/更新它!
解决方案2)
自定义属性:
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDate { get; set; }
Entity Framework 6 Code first Default value
解决方案3)
在Computed:
的帮助下[Required, DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedUtc { get; set;
"dbo.Products",
c => new
{
ProductId = c.Int(nullable: false, identity: true),
Name = c.String(),
CreatedUtc = c.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"),
})
.PrimaryKey(t => t.ProductId);
解决方案4) 您也可以通过手动修改查询来执行命令拦截器。
解决方案5) 使用Repository模式管理数据创建并通过CreateNew进行设置 这是我最喜欢的解决方案!
https://msdn.microsoft.com/en-us/library/ff649690.aspx
解决方案6) 只需在UI或虚拟机中设置或进入。
Entity Framework Core 1.0 easy:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Passage>()
.Property(b => b.CreatedDate )
.HasDefaultValueSql("getdate()");
}
答案 1 :(得分:5)
对于那些使用异步系统(SaveChangesAsync)和.net核心的人来说,最好将下面的代码添加到DbContext类。
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
var AddedEntities = ChangeTracker.Entries().Where(E => E.State == EntityState.Added).ToList();
AddedEntities.ForEach(E =>
{
E.Property("CreationTime").CurrentValue = DateTime.Now;
});
var EditedEntities = ChangeTracker.Entries().Where(E => E.State == EntityState.Modified).ToList();
EditedEntities.ForEach(E =>
{
E.Property("ModifiedDate").CurrentValue = DateTime.Now;
});
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
您也可以定义类或接口,如下所示。
public class SaveConfig
{
public DateTime CreationTime { get; set; }
public DateTime? ModifiedDate { get; set; }
}
只是从SaveConfig类继承实体。
答案 2 :(得分:4)
如果您使用的是代码,可以试试这个
[Required, DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedDate { get; set; }
迁移
AddColumn("Passage", "CreatedDate", n => n.DateTime(nullable: false, defaultValueSql: "GETDATE()"));
更多参考here,similar answer
或者您可以全局覆盖
saveChanges
注意*如果您拥有CreatedDate
字段,则会对整个模型产生影响
public override int SaveChanges()
{
DateTime saveTime = DateTime.Now;
foreach (var entry in this.ChangeTracker.Entries()
.Where(e => e.State == (EntityState) System.Data.EntityState.Added))
{
if (entry.Property("CreatedDate").CurrentValue == null)
entry.Property("CreatedDate").CurrentValue = saveTime;
}
return base.SaveChanges();
}
答案 3 :(得分:1)
使用 SaveChangesAsync 的另一种方法是,您可以为相应的数据库创建数据库触发器。我制作了一个gist,其中包含用于 mssql,postgress,sqlite和mysql 的一些辅助功能。这是代码的粘贴。
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.
*/
/// <summary>
/// needed for non mysql implementation to update a datetime on a record update
/// </summary>
/// <param name="databaseProvider"></param>
/// <param name="name"></param>
/// <param name="table"></param>
/// <param name="column"></param>
/// <param name="schema"></param>
/// <param name="id_column"></param>
/// <returns></returns>
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('" + 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<DateTime>(type: dbKeys.dateTime, nullable: true, defaultValueSql: dbKeys.DEFAULTDATE_CREATE),
updated_at = table.Column<DateTime>(type: dbKeys.dateTime, nullable: true, defaultValueSql: dbKeys.DEFAULTDATE_UPDATE)
*/
/// <summary>
/// Can get specific formats for different databases. Supports mssql, postgress, sqlite, and mysql.
/// </summary>
/// <param name="databaseProvider"></param>
/// <returns></returns>
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;
}
}
}
答案 4 :(得分:1)
PostgreSQL中CreationDate的解决方案:
builder.Property(e => e.CreationDate)
.HasColumnType("timestamp without time zone")
.HasDefaultValueSql("NOW()")
.ValueGeneratedOnAdd();
不幸的是,根据文档,http://www.npgsql.org/efcore/value-generation.html#computed-columns-on-add-or-update
尚无针对更新事件的解决方案答案 5 :(得分:-2)
太简单了,只需执行2步:
1。创建模型,其中这些字段位于createDate
字段的顶部:
[Required, DatabaseGenerated(DatabaseGeneratedOption.Computed)]
2。创建迁移后,在其文件中更新此部分的数据库编辑列,并像这样添加defaultValueSql: "getdate()"
:
id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
CreatedDate = table.Column<DateTime>(defaultValueSql: "getdate()",nullable: false)