Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架/SQL2008-如何自动更新实体的LastModified字段?_C#_.net_Sql Server 2008_Entity Framework 4_Datetime Generation - Fatal编程技术网

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表

我如何自动

  • 将记录的CreatedOn/LastModified字段设置为“现在”(插入时)
  • 将记录的LastModified字段设置为现在(执行更新时)
  • 当我自动说时,我的意思是我希望能够做到:

    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;
    ((基数)