EF6和EF4之间的更改跟踪行为已更改。如何恢复到Ef4的行为?

时间:2014-11-05 23:15:13

标签: entity-framework entity-framework-4 entity-framework-6

EF4 中从数据库加载实体并将其属性设置为与之前相同的值仍然会导致向数据库发出更新。

EF6 中,实体似乎意识到属性值没有改变,因此不会导致向DB发出更新。

是否有可能在EF6中获得EF4行为?

我尝试了什么:

  1. 设置" context.Configuration.AutoDetectChangesEnabled = false;"。这没用。
  2. Hail Mary:context.Configuration.ValidateOnSaveEnabled = false;这也行不通。
  3. ((IObjectContextAdapter)context).ObjectContext.ContextOptions.UseLegacyPreserveChangesBehavior = true;没用?
  4. 我需要旧的EF4行为的原因是因为用于依赖某些触发器来更新字段的代码(ModifiedDate)和以前的EF4总是会导致保存,而现在EF6不会这样做,这将导致主要的回归头痛!

    我用来测试此代码的一些代码:

    public void UpdateScenarioWithNoChangesCausesEfToNotPersistChanges()
    {
        using (
            TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
            {
                IsolationLevel = IsolationLevel.ReadCommitted
            }))
        {
            using (EnterpriseModel context = new EnterpriseModel())
            {
                //context.Configuration.AutoDetectChangesEnabled = false; //did not work
                //context.Configuration.ValidateOnSaveEnabled = false; //did not work
                //((IObjectContextAdapter) context).ObjectContext.ContextOptions.UseLegacyPreserveChangesBehavior = true; //did not work
    
                Guid id = new Guid("3321dbaf-c55e-e411-80cf-00155d0d70c0");
                var efScenario = (from s in context.Scenario
                                  where s.ScenarioId == id
                                  select s).First();
    
                DateTime modifiedDateBeforeChanges = efScenario.ModifiedDate;
                //just setting the value back to itself.
                efScenario.ModifiedBy = efScenario.ModifiedBy;
    
                context.SaveChanges();
                //ef scenario object's ModifiedDate is set as a Computed 
                DateTime modifiedDateAfterChanges = efScenario.ModifiedDate;
                //There is a trigger on Updates that sets the modifiedDate in the database.
                //also ModifiedDate is set as a computed column.
    
                //the following passes for EF4 and fails for EF6.
                //If in EF6 i do make a change to efScenario.ModifiedBy = efScenario.ModifiedBy; 
                //then EF6 works!
                Assert.AreNotEqual(modifiedDateBeforeChanges, modifiedDateAfterChanges);
            }
        }
    
    }
    

    有效的方法:

    1. 我可以将ModifiedDate列更改为某个新值,这会导致EF检测到更改并导致保存。触发器更新修改日期,然后因为列被标记为计算,EF将检索该值。 (不要喜欢!因为我必须通过调用SaveChanges的每个方法,并确保以前更新过的每个实体都使用新的ModifiedDate值进行更新。

    2. 在调用SaveChanges之前调用 context.Entry(efScenario).State = EntityState.Modified; 。在我看来,这并不比(1)好。我现在可能会选择1。

    3. 我理想的解决方案: 我可以在EF中切换的设置,这将允许我获得EF4的先前行为。

      奖金问题: 这种行为何时在EF中发生变化?我似乎找不到任何关于这种变化的文件!

      表格结构

      CREATE TABLE [dbo].[Scenario](
          [ScenarioId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Scenario_ScenarioId]  DEFAULT (newsequentialid()),
          [Name] [varchar](200) NOT NULL,
          [ModifiedBy] [varchar](100) NOT NULL,
          [ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_Scenario_ModifiedDate]  DEFAULT (getdate()),
       CONSTRAINT [PK_Scenario] PRIMARY KEY CLUSTERED 
      (
          [ScenarioId] ASC
      )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
      ) ON [PRIMARY]
      
      GO
      
      
      CREATE TRIGGER  [dbo].[trUpdateModifiedDateScenario]
                    ON  [dbo].[Scenario]
                    INSTEAD OF UPDATE
      
      AS
      BEGIN
          SET NOCOUNT ON;
      
              UPDATE a  SET a.[Name]=b.[Name]
                  , a.[ModifiedBy]=b.[ModifiedBy]
                  , a.[ModifiedDate]=GETDATE()
              FROM [dbo].[Scenario] a 
              INNER JOIN inserted b 
                 ON a.[ScenarioId]=b.[ScenarioId]
      
          END;
      GO
      

1 个答案:

答案 0 :(得分:1)

您应该能够告诉EF模型已更改:

var efScenario = (from s in context.Scenario
                  where s.ScenarioId == id
                  select s).First();

context.Entry(efSCenario).State = EntityState.Modified;

context.SaveChanges();  //Should hit the database, it's marked as modified.

MSDN DbContext.Entry()

MSDN EntityState

  

如何恢复到Ef4行为?

我不相信有一些全局方法可以恢复行为,您将不得不手动执行此操作。