Получить все отслеживаемые объекты из DbContext?
Многие из таблиц в моей базе данных должны иметь столбец "DateCreated" и "DateModified". Я хочу обновлять эти столбцы всякий раз, когда вызывается SaveChanges()
.
Все мои объекты модели наследуют от класса AbstractModel
, чтобы разрешить такое поведение. Класс выглядит следующим образом:
public abstract class AbstractModel {
public virtual void UpdateDates() { }
}
Затем я планирую переопределить UpdateDates()
в любых дочерних классах, у которых есть поля DateCreated
и DateModified
, которые они должны поддерживать.
Чтобы использовать это, мне нужно получить список всех объектов, которые отслеживает DbContext
, и вызвать UpdateDates()
на них, если объект помечен как Added
или Modified
.
Кажется, я не могу получить доступ к тому, где DbContext
хранит эту информацию. Я могу сделать dbContext.Entry(object).State
, чтобы получить EntityState
одного объекта, но я не могу понять, как получить список всех отслеживаемых объектов.
Как это сделать?
Ответы
Ответ 1
Я думаю, вы можете использовать ChangeTracker для этого:
public class MyContext : DbContext
{
//...
public override int SaveChanges()
{
foreach (var dbEntityEntry in ChangeTracker.Entries<AbstractModel>())
{
dbEntityEntry.Entity.UpdateDates();
}
return base.SaveChanges();
}
}
Ответ 2
Принятое решение здесь лучше для выше EF4, чем предложение ObjectContext - мы столкнулись с проблемами, например, в памяти db, которую мы использовали в тестовом контексте, не работающем хорошо с вышеупомянутым решением (получение состояния "Отдельно" для некоторых измененных записей в сценариях наследования). Это решение использует собственный способ DbContext для поиска отслеживаемых объектов:
context.ChangeTracker.Entries()
.Where (t => t.State == EntityState.Modified)
Ответ 3
Это хорошо работает в нашем проекте, поэтому нам не нужно забывать переопределять что-то каждый раз, когда мы добавляем новый объект, у которого есть наше стандартное свойство LastUpdatedDateTime.
Использование EF4; для EF5 DbContext я думаю ((IObjectContextAdapter) _dbContext).ObjectContext.ObjectStateManager предоставит вам диспетчер состояний объекта:
// In our SaveChanges wrapper:
var entries = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted);
private static void PopulateDate(IEnumerable<ObjectStateEntry> entries)
{
foreach (var entry in entries)
{
if (entry.State != EntityState.Deleted)
{
if ((entry.Entity != null) && (entry.Entity.GetType().GetProperty("LastUpdatedDateTime") != null))
{
((dynamic)entry.Entity).LastUpdatedDateTime = DateTime.UtcNow;
}
}
}
}
Вызов отражения не является проблемой: для объекта с 25 свойствами (много), миллион запросов отражения принимает avg ~ 210 мс.