У меня проблема с чем-то, что кажется ошибкой в Entity Framework 4.1: я добавил обработчик на ObjectContext.SavingChanges
, который обновляет свойство "LastModified" всякий раз, когда объект добавляется или изменяется в базе данных.Затем я делаю следующее:
- Добавление двух объектов в базу данных и отправка (вызов
SaveChanges()
) - Изменение первого добавленного объекта
- Извлечениедва объекта, упорядоченные по LastModified
Полученные объекты возвращаются в неправильном порядке.Глядя на объекты, я вижу, что свойство LastModified обновлено.Другими словами, событие SavingChanges было запущено правильно.Но, глядя в базу данных, столбец LastModified не был изменен.То есть теперь существует разница между кэшированными объектами EF и строками в базе данных.
Я попытался выполнить то же обновление до LastModified в переопределенном методе "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);
}
}
}
}
Я должен добавить, что SavingChangesОбработчик работал нормально до того, как мы обновились до EF4.1 и использовали Code-First (то есть он работал в EF4.0 с model-first)
Вопрос в том, нашел ли я здесь ошибку, или ясделал что-то не так?