RPM*_*984 41 .net c# 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; }
}
Run Code Online (Sandbox Code Playgroud)
这对应于具有相同名称/属性的SQL Server 2008表...
我怎么能自动:
当我自动说,我的意思是我希望能够做到这一点:
poco.Name = "Changing the name";
repository.Save();
Run Code Online (Sandbox Code Playgroud)
不是这个:
poco.Name = "Changing the name";
poco.LastModified = DateTime.Now;
repository.Save();
Run Code Online (Sandbox Code Playgroud)
在幕后,"某事"应该自动更新日期时间字段.什么是"东西"?
我正在使用Entity Framework 4.0 - 有没有一种方法可以让EF为我自动执行此操作?(EDMX中的特殊设置可能?)
从SQL Server端,我可以使用DefaultValue,但这只适用于INSERT(不是UPDATE).
类似地,我可以使用POCO上的构造函数设置默认值,但这只会在实例化对象时起作用.
当然我可以使用触发器,但它并不理想.
因为我正在使用Entity Framework,我可以挂钩到SavingChanges事件并在这里更新日期字段,但问题是我需要"了解"POCO(目前,我的存储库是用泛型实现的).我需要做一些OO技巧(比如让我的POCO实现一个接口,然后调用一个方法).我并不反对,但如果我必须这样做,我宁愿手动设置字段.
我基本上在寻找SQL Server 2008或Entity Framework 4.0解决方案.(或智能的.NET方式)
有任何想法吗?
编辑
感谢@marc_s的答案,但我选择了一个更适合我的方案的解决方案.
Nic*_*ick 53
我知道我参加聚会的时间有点晚了,但我刚刚解决了这个项目,我正在研究并认为我会分享我的解决方案.
首先,为了使解决方案更易于重用,我创建了一个带有timestamp属性的基类:
public class EntityBase
{
public DateTime? CreatedDate { get; set; }
public DateTime? LastModifiedDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后我覆盖了我的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();
}
}
Run Code Online (Sandbox Code Playgroud)
因为我有一个服务层在我的控制器(我使用ASP.NET MVC)和我的存储库之间进行调解,所以我决定在这里自动设置字段.
此外,我的POCO没有关系/抽象,它们完全独立.我想保持这种方式,而不是标记任何虚拟属性,或创建基类.
所以我创建了一个接口,IAutoGenerateDateFields:
public interface IAutoGenerateDateFields
{
DateTime LastModified { get;set; }
DateTime CreatedOn { get;set; }
}
Run Code Online (Sandbox Code Playgroud)
对于任何POCO我希望自动生成这些字段,我实现这个接口.
使用我的问题中的示例:
public class PocoWithDates : IAutoGenerateDateFields
{
public string PocoName { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime LastModified { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在我的服务层,我现在检查具体对象是否实现了接口:
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.
}
Run Code Online (Sandbox Code Playgroud)
我稍后可能会在Add to a helper/extension方法中破坏该代码.
但我认为这对我的场景来说是一个不错的解决方案,因为我不想在Save上使用虚拟(因为我使用的是工作单元,存储库和Pure POCO),并且不想使用触发器.
如果您有任何想法/建议,请告诉我.
我还想提出一个迟到的解决方案.这个仅适用于.NET Framework 4,但使这类任务变得微不足道.
var vs = oceContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach (var v in vs)
{
dynamic dv = v.Entity;
dv.DateLastEdit = DateTime.Now;
}
Run Code Online (Sandbox Code Playgroud)
这是以前回复的编辑版本.以前的一个不适合我的更新.
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();
}
Run Code Online (Sandbox Code Playgroud)