我在Entity Framework 4.1中遇到了一個似乎是錯誤的問題:我在ObjectContext.SavingChanges
上添加了一個處理程序,它在每次對象被更新時更新屬性「LastModified」添加到數據庫中或在數據庫中修改。然後,我做到以下幾點:實體框架4.1 ObjectContext.SavingChanges中的錯誤處理(?)
- 添加兩個對象到數據庫,並提交(調用
SaveChanges()
) - 修改已添加
- 提取由上次更改
生成的對象以錯誤的順序返回。看着對象,我可以看到LastModified屬性已經更新。換句話說,SavingChanges事件被正確觸發。但是查看數據庫,LastModified列沒有被更改。也就是說,現在EF的緩存對象與數據庫中的行之間存在差異。
我試圖在重寫「的SaveChanges」方法執行相同的更新到上次更改時間:
public override int SaveChanges()
{
SaveChangesHandler();//updating LastModified property on all objects
return base.SaveChanges();
}
這樣做造成的數據庫中進行適當的更新和查詢依次返回的對象。
這裏是一個完整的測試程序顯示錯誤:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace TestApplication
{
class Program
{
private PersistenceContext context;
private static void Main(string[] args)
{
var program = new Program();
program.Test();
}
public void Test()
{
SetUpDatabase();
var order1 = new Order {Name = "Order1"};
context.Orders.Add(order1);
var order2 = new Order {Name = "Order2"};
context.Orders.Add(order2);
context.SaveChanges();
Thread.Sleep(1000);
order1 = GetOrder(order1.Id); // Modified 1.
order1.Name = "modified order1";
context.SaveChanges();
List<Order> orders = GetOldestOrders(1);
AssertEquals(orders.First().Id, order2.Id);//works fine - this was the oldest object from the beginning
Thread.Sleep(1000);
order2 = GetOrder(order2.Id); // Modified 2.
order2.Name = "modified order2";
context.SaveChanges();
orders = GetOldestOrders(1);
AssertEquals(orders.First().Id, order1.Id);//FAILS - proves that the database is not updated with timestamps
}
private void AssertEquals(long id1, long id2)
{
if (id1 != id2) throw new Exception(id1 + " != " + id2);
}
private Order GetOrder(long id)
{
return context.Orders.Find(id);
}
public List<Order> GetOldestOrders(int max)
{
return context.Orders.OrderBy(order => order.LastModified).Take(max).ToList();
}
public void SetUpDatabase()
{
//Strategy for always recreating the DB every time the app is run.
var dropCreateDatabaseAlways = new DropCreateDatabaseAlways<PersistenceContext>();
context = new PersistenceContext();
dropCreateDatabaseAlways.InitializeDatabase(context);
}
}
////////////////////////////////////////////////
public class Order
{
public virtual long Id { get; set; }
public virtual DateTimeOffset LastModified { get; set; }
public virtual string Name { get; set; }
}
////////////////////////////////////////////////
public class PersistenceContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public PersistenceContext()
{
Init();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
public void Init()
{
((IObjectContextAdapter) this).ObjectContext.SavingChanges += SavingChangesHandler;
Configuration.LazyLoadingEnabled = true;
}
private void SavingChangesHandler(object sender, EventArgs e)
{
DateTimeOffset now = DateTimeOffset.Now;
foreach (DbEntityEntry entry in ChangeTracker.Entries()
.Where(entity => entity.State == EntityState.Added || entity.State == EntityState.Modified))
{
SetModifiedDate(now, entry);
}
}
private static void SetModifiedDate(DateTimeOffset now, DbEntityEntry modifiedEntity)
{
if (modifiedEntity.Entity == null)
{
return;
}
PropertyInfo propertyInfo = modifiedEntity.Entity.GetType().GetProperty("LastModified");
if (propertyInfo != null)
{
propertyInfo.SetValue(modifiedEntity.Entity, now, null);
}
}
}
}
我要補充一點,之前我們升級到EF4.1並使用代碼優先(也就是SavingChanges處理工作得很好,它在工作EF4 .0與模型優先)
問題是:我在這裏發現了一個錯誤,或者我做錯了什麼?
謝謝您的回答。你的建議實際上奏效了!但我認爲它看起來有點像黑客 - 當我修改一個屬性時,不應該由框架自動處理這個問題嗎?正如我在我的問題中寫的,相同的代碼在EF4.0中工作正常。 – JRV 2011-05-05 06:14:26
@JRV看看我的編輯 – Till 2011-05-05 09:52:11
很好 - 再次感謝。這是一個更清潔的方法,我會爲此而努力。我只會接受PropertyInfo.SetValue不起作用的事實,現在我知道了另一種方法來做到這一點:-) – JRV 2011-05-06 05:41:36