C# 实体框架/SQL2008-如何自动更新实体的LastModified字段?
如果我有以下实体:C# 实体框架/SQL2008-如何自动更新实体的LastModified字段?,c#,.net,sql-server-2008,entity-framework-4,datetime-generation,C#,.net,Sql Server 2008,Entity Framework 4,Datetime Generation,如果我有以下实体: public class PocoWithDates { public string PocoName { get; set; } public DateTime CreatedOn { get; set; } public DateTime LastModified { get; set; } } 对应于具有相同名称/属性的SQL Server 2008表 我如何自动: 将记录的CreatedOn/LastModified字段设置为“现在”(插入时) 将
public class PocoWithDates
{
public string PocoName { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime LastModified { get; set; }
}
对应于具有相同名称/属性的SQL Server 2008表
我如何自动:
poco.Name = "Changing the name";
repository.Save();
不是这个:
poco.Name = "Changing the name";
poco.LastModified = DateTime.Now;
repository.Save();
在幕后,“something”应该自动更新datetime字段。那是什么“东西”
我正在使用EntityFramework4.0-有没有一种方法可以让EF自动为我做到这一点?(可能是EDMX中的特殊设置?)
在SQL Server端,我可以使用DefaultValue,但这只适用于插入的(而不是更新的)
类似地,我可以使用POCO上的构造函数设置默认值,但这同样只在实例化对象时起作用
当然我可以使用触发器,但这并不理想
因为我使用的是实体框架,所以我可以钩住SavingChanges事件并更新此处的日期字段,但问题是我需要“意识到”POCO(目前,我的存储库是用泛型实现的)。我需要做一些面向对象的技巧(比如让我的POCO实现一个接口,并在此基础上调用一个方法)。我不反对这样做,但如果我必须这样做,我宁愿手动设置字段
我基本上是在寻找SQL Server 2008或Entity Framework 4.0解决方案。(或智能.NET方式)
有什么想法吗
编辑
感谢@marc_s的回答,但我选择了一个更适合我的场景的解决方案。您有两个选择:
- 为所有执行以下操作的业务实体类创建一个基类
在所有其他人都必须调用的虚拟poco.LastModified = DateTime.Now;
方法中.Save()
- 在数据库中使用触发器
我不认为有任何其他合理的安全和简单的方法来实现这一点。由于我有一个服务层在我的控制器(我使用ASP.NET MVC)和我的存储库之间进行中介,我决定在这里自动设置字段
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace TestDatamodel
{
public partial class DiagnosisPrescriptionManagementEntities
{
public override int SaveChanges()
{
ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;
foreach (ObjectStateEntry entry in
(context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified)))
{
if (!entry.IsRelationship)
{
CurrentValueRecord entryValues = entry.CurrentValues;
if (entryValues.GetOrdinal("ModifiedBy") > 0)
{
HttpContext currentContext = HttpContext.Current;
string userId = "nazrul";
DateTime now = DateTime.Now;
if (currContext.User.Identity.IsAuthenticated)
{
if (currentContext .Session["userId"] != null)
{
userId = (string)currentContext .Session["userId"];
}
else
{
userId = UserAuthentication.GetUserId(currentContext .User.Identity.UserCode);
}
}
if (entry.State == EntityState.Modified)
{
entryValues.SetString(entryValues.GetOrdinal("ModifiedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("ModifiedDate"), now);
}
if (entry.State == EntityState.Added)
{
entryValues.SetString(entryValues.GetOrdinal("CreatedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("CreatedDate"), now);
}
}
}
}
return base.SaveChanges();
}
}
}
此外,我的POCO没有关系/抽象,它们完全独立。我希望保持这种方式,不标记任何虚拟属性,也不创建基类
所以我创建了一个接口,IAutoGenerateDateFields:
public interface IAutoGenerateDateFields
{
DateTime LastModified { get;set; }
DateTime CreatedOn { get;set; }
}
对于我希望自动生成这些字段的任何POCO,我实现了这个接口
用我问题中的例子:
public class PocoWithDates : IAutoGenerateDateFields
{
public string PocoName { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime LastModified { get; set; }
}
在我的服务层中,我现在检查具体对象是否实现了接口:
public void Add(SomePoco poco)
{
var autoDateFieldsPoco = poco as IAutoGenerateDateFields; // returns null if it's not.
if (autoDateFieldsPoco != null) // if it implements interface
{
autoDateFieldsPoco.LastModified = DateTime.Now;
autoDateFieldsPoco.CreatedOn = DateTime.Now;
}
// ..go on about other persistence work.
}
稍后,我可能会在附加到帮助程序/扩展方法中中断该代码
但我认为这对于我的场景来说是一个不错的解决方案,因为我不想在Save上使用virtuals(因为我使用的是工作单元、存储库和纯POCO),也不想使用触发器
如果您有任何想法/建议,请告诉我。我知道我参加聚会有点晚了,但我刚刚为一个正在进行的项目解决了这个问题,并想与大家分享我的解决方案 首先,为了使解决方案更加可重用,我创建了一个具有时间戳属性的基类:
public class EntityBase
{
public DateTime? CreatedDate { get; set; }
public DateTime? LastModifiedDate { get; set; }
}
然后我在我的DbContext上重写了SaveChanges方法:
public class MyContext : DbContext
{
public override int SaveChanges()
{
ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;
//Find all Entities that are Added/Modified that inherit from my EntityBase
IEnumerable<ObjectStateEntry> objectStateEntries =
from e in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
where
e.IsRelationship == false &&
e.Entity != null &&
typeof(EntityBase).IsAssignableFrom(e.Entity.GetType())
select e;
var currentTime = DateTime.Now;
foreach (var entry in objectStateEntries)
{
var entityBase = entry.Entity as EntityBase;
if (entry.State == EntityState.Added)
{
entityBase.CreatedDate = currentTime;
}
entityBase.LastModifiedDate = currentTime;
}
return base.SaveChanges();
}
}
公共类MyContext:DbContext
{
公共覆盖int SaveChanges()
{
ObjectContext上下文=((IObjectContextAdapter)this).ObjectContext;
//查找从我的EntityBase继承的所有添加/修改的实体
IEnumerable objectStateEntries=
从context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)中的e
哪里
e、 IsRelationship==错误&&
e、 实体!=null&&
typeof(EntityBase).IsAssignableFrom(e.Entity.GetType())
选择e;
var currentTime=DateTime.Now;
foreach(objectStateEntries中的var条目)
{
var entityBase=entry.Entity作为entityBase;
if(entry.State==EntityState.Added)
{
entityBase.CreatedDate=当前时间;
}
entityBase.LastModifiedDate=当前时间;
}
返回base.SaveChanges();
}
}
我还想提出一个迟来的解决方案。这一项仅适用于.NETFramework4,但使这类任务变得微不足道
var vs = oceContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach (var v in vs)
{
dynamic dv = v.Entity;
dv.DateLastEdit = DateTime.Now;
}
我们可以使用分部类和重写SaveChanges方法来实现这一点
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace TestDatamodel
{
public partial class DiagnosisPrescriptionManagementEntities
{
public override int SaveChanges()
{
ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;
foreach (ObjectStateEntry entry in
(context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified)))
{
if (!entry.IsRelationship)
{
CurrentValueRecord entryValues = entry.CurrentValues;
if (entryValues.GetOrdinal("ModifiedBy") > 0)
{
HttpContext currentContext = HttpContext.Current;
string userId = "nazrul";
DateTime now = DateTime.Now;
if (currContext.User.Identity.IsAuthenticated)
{
if (currentContext .Session["userId"] != null)
{
userId = (string)currentContext .Session["userId"];
}
else
{
userId = UserAuthentication.GetUserId(currentContext .User.Identity.UserCode);
}
}
if (entry.State == EntityState.Modified)
{
entryValues.SetString(entryValues.GetOrdinal("ModifiedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("ModifiedDate"), now);
}
if (entry.State == EntityState.Added)
{
entryValues.SetString(entryValues.GetOrdinal("CreatedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("CreatedDate"), now);
}
}
}
}
return base.SaveChanges();
}
}
}
以下是先前回复的编辑版本。前一个对我来说不适用于更新
public override int SaveChanges()
{
var objectStateEntries = ChangeTracker.Entries()
.Where(e => e.Entity is TrackedEntityBase && (e.State == EntityState.Modified || e.State == EntityState.Added)).ToList();
var currentTime = DateTime.UtcNow;
foreach (var entry in objectStateEntries)
{
var entityBase = entry.Entity as TrackedEntityBase;
if (entityBase == null) continue;
if (entry.State == EntityState.Added)
{
entityBase.CreatedDate = currentTime;
}
entityBase.LastModifiedDate = currentTime;
}
return base.SaveChanges();
}
必须添加基本实体,并从数据库的第一个部分类扩展它(这并不理想)
public override int SaveChanges()
{
AddTimestamps();
返回base.SaveChanges();
}
公共重写异步任务SaveChangesAsync()
{
AddTimestamps();
return wait base.SaveChangesAsync();
}
私有void AddTimestamps()
{
//var entities=ChangeTracker.Entries()。其中(x=>x.Entity为BaseEntity&(x.State==EntityState.Added | | x.State==EntityState.Modified));
//ObjectVeContext上下文=((IOObjectContextAdapter)this).ObjectContext;
var entities=ChangeTracker.Entries()。其中(e=>e.Entity是BaseEntity&(e.State==EntityState.Modified | | e.State==EntityState.Added)).ToList();
var currentUsername=!string.IsNullOrEmpty(System.Web.HttpContext.Current?.User?.Identity?.Name)
?HttpContext.Current.User.Identity.Name
:“匿名”;
foreach(实体中的var实体)
{
if(entity.State==EntityState.Added)
{
((BaseEntity)entity.entity).CREATEDON=DateTime.UtcNow;
((基数)