【问题标题】:How to auto-update the Modified property on a Entity in Entity Framework 4 when saving?保存时如何自动更新Entity Framework 4中实体的Modified属性?
【发布时间】:2010-10-12 19:07:36
【问题描述】:

我在 VS2010、POCO 和模型优先方法中使用 EF4。

我的实体具有以下属性:Id:Guid、Name:String、Created:DateTime、Modified:DateTime、Revision:Int32。

我创建我的实体,设置名称并使用 EF4 上下文将其保存到数据库中。这应该将 Id 设置为新的 Guid(与 Identity-SGP 一起使用),Created 设置为 now,Modified 保留为 null,Revision 设置为 0。我检索实体,更改名称并再次保存。这次 Modified-value 应该设置为 now 并且 revision 应该是 1。

如何使用 EF4 和 EDMX-designer 最好地完成此任务?

更新:

这就是我最终使用的:

public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
    foreach (ObjectStateEntry entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Where(e => e.Entity is EntityBase))
    {
        EntityBase entity = entry.Entity as EntityBase;
        if (entry.State == EntityState.Added)
        {
            entity.Version = new Version() { Major = 1, Minor = 0, Revision = 0 };
            entity.Created = DateTime.Now;
            if (OperationContext.Current != null) entity.CreatedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
        }
        else if (entry.State == EntityState.Modified)
        {
            entity.Version.Revision++;
            entity.Modified = DateTime.Now;
            if (OperationContext.Current != null) entity.ModifiedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
        }
    }

    return base.SaveChanges(options);
}

哪个不起作用... :(

问题是即使我显式运行 MarkAsModified() 方法,entry.State 仍然未修改。我不明白这个...

为什么默认不启用更改跟踪?我使用自我跟踪实体,为什么我要关闭它并每次都明确打开它?为什么即使状态未修改,实体也会持久化到数据库? EntityState 和 ObjectState 有什么区别?目前我在服务器端进行所有更改和更新,但一段时间后我还将使用 WCF 服务来回传输实体......这里如何处理更改有区别吗?如果服务器端的所有更改,无论更改跟踪开/关,都保持不变?我想要的是,如果不更新 Modified、Revision 等,就不能存储任何东西。当对象被接收并发生更改时,应该始终在服务器上设置这些属性。 (我这里说的不是 sql-server-side,而是 service-server-side)

【问题讨论】:

    标签: c# .net entity-framework entity-framework-4 ef-model-first


    【解决方案1】:

    假设您的实体类型名称是产品:

    partial void OnContextCreated() {
        this.SavingChanges += Context_SavingChanges;
    }
    
    void Context_SavingChanges(object sender, EventArgs e) {
    
        IEnumerable objectStateEntries =
                from ose
                in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | 
                                                                EntityState.Modified)
                where ose.Entity is Product
                select ose;
    
        Product product = objectStateEntries.Single().Entity as Product;
    
        product.ModifiedDate = DateTime.Now;
        product.ComplexProperty.Revision++;
    }
    


    如果您希望使用此代码为您的所有实体填充公共字段,例如 ModifiedDate 或 ModifiedBy,请查看此帖子:
    Entity Framework - Auditing Activity

    顺便说一句,StoreGeneratedPatternConcurrencyMode 与此无关,它们用于完全不同且不相关的东西。

    【讨论】:

    • 谢谢,我会试试看,但是有什么方法可以在更新时在 sql-server 上执行此操作吗?
    • 当然,您可以编写一个数据库“触发器”,在插入和更新时更新表。这是使用实体框架在客户端执行此操作的解决方案。
    • 我已经尝试过您的方法,但在更新实体的 ComplexType-property 内设置 int-property 时遇到问题。我有一个具有三个整数的 ComplexType 版本,我只想更新最后一个值。设置新版本完全失败,异常告诉我必须实现 IExtendedDataRecord。真的有必要吗?
    • 另外,这个方法有点复杂。正如雅各布所建议的那样,是否有任何方法可以使用我的实体对象?那会简单得多。但是使用他的方法我没有得到任何新创建的对象,只有现有的对象。我猜他们还没有真正添加到 ObjectSet 中?
    • 好的,我在我的回答中针对您的场景发布了一个代码 sn-p。顺便说一句,如果您使用的是 POCO,那么您应该首先更改 T4 模板以调用 OnContextCreated() 方法,以便您可以成功订阅 SavingChanges 事件。
    【解决方案2】:

    我个人偏爱基于客户端代码的解决方案。由于您使用的是 POCO,因此让对象本身进行更新可能是最简单的。更新 Name 属性上的 set 访问器以调用更改 Modified 和 Revision 属性的“objectModified”方法。

    如果由于更改属性的时间和保存对象的时间之间的时间差而使这令人不快,您可以利用实体​​对象上的分部类。这样做将允许您覆盖 SaveChanges 方法,您可以在其中触摸实体对象上的 ObjectSet 属性中的实体。比如:

    public partial class YourEntities
    {
        public override int SaveChanges(System.Data.Objects.SaveOptions options)
        {
            //update your objects here
            return base.SaveChanges(options);
        }
    }
    

    【讨论】:

    • 但是,如果我从其他不使用 EF4 的地方更新我的 SQL,我仍然希望增加修订列,如果修改列也发生了变化,那就太好了。我必须考虑一下,我可能会使用组合解决方案。感谢您的回复!
    • 我尝试了您建议的方法,但是当添加新对象时,它们不会出现在我的 context.Entities 中。它是空的……知道为什么吗?
    • 注意到我必须显式运行 entity.StartTracking() 才能将状态更改为已修改。我怎样才能让它默认开启?为什么当 ChangeTracking 关闭且 State == Unchanged 时运行 SaveChanges() 时我的更改会被保存???奇怪...
    • 如果您需要跨多个应用程序进行持久化,您需要共享一个库或在数据库级别使用触发器。如果您已将一个对象添加到您的上下文或通过您的上下文检索它,那么它应该出现在该实体的 ObjectSet 中。
    【解决方案3】:

    我们可以使用部分类并重写 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();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多