Обновить одно свойство записи в Entity Framework Code First
Как я могу обновить одно свойство записи, не извлекая его первым?
Я спрашиваю в контексте EF Code First 4.1
Говорит, что у меня есть класс User, сопоставление с таблицей Пользователи в базе данных:
class User
{
public int Id {get;set;}
[Required]
public string Name {get;set;}
public DateTime LastActivity {get;set;}
...
}
Теперь я хочу обновить LastActivity пользователя. У меня есть идентификатор пользователя. Я легко могу сделать это, запросив запись пользователя, установить новое значение в LastActivity, а затем вызвать SaveChanges(). Но это приведет к избыточному запросу.
Я работаю с помощью метода Attach. Но поскольку EF выбрасывает исключение проверки на Name, если оно null, я устанавливаю Name в случайную строку (не будет обновляться до DB). Но это не выглядит элегантным решением:
using (var entities = new MyEntities())
{
User u = new User {Id = id, Name="this wont be updated" };
entities.Users.Attach(u);
u.LastActivity = DateTime.Now;
entities.SaveChanges();
}
Я был бы очень appriciate, если кто-то может предоставить мне лучшее решение. И простите меня за любую ошибку, поскольку это первый раз, когда я задал вопрос о SO.
Ответы
Ответ 1
Это проблема реализации валидации. Валидация способна проверять только целое сущность. Он не проверяет только измененные свойства, как ожидалось. Из-за этого проверка должна быть отключена в сценариях, где вы хотите использовать неполные фиктивные объекты:
using (var entities = new MyEntities())
{
entities.Configuration.ValidateOnSaveEnabled = false;
User u = new User {Id = id, LastActivity = DateTime.Now };
entities.Users.Attach(u);
entities.Entry(user).Property(u => u.LastActivity).IsModified = true;
entities.SaveChanges();
}
Это, очевидно, проблема, если вы хотите использовать тот же контекст для обновления фиктивных объектов и для обновления целых объектов, где должна использоваться валидация. Проверка выполняется в SaveChanges
, поэтому вы не можете сказать, какие объекты должны быть проверены, а какие нет.
Ответ 2
Вы можете попробовать что-то вроде взлома:
context.Database.ExecuteSqlCommand("update [dbo].[Users] set [LastActivity] = @p1 where [Id] = @p2",
new System.Data.SqlClient.SqlParameter("p1", DateTime.Now),
new System.Data.SqlClient.SqlParameter("p2", id));
Ответ 3
Я сейчас занимаюсь этим прямо сейчас. То, что я решил сделать, это переопределить метод ValidateEntity в контексте БД.
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
var errors = new List<DbValidationError>();
foreach (var error in result.ValidationErrors)
{
if (entityEntry.Property(error.PropertyName).IsModified)
{
errors.Add(error);
}
}
return new DbEntityValidationResult(entityEntry, errors);
}
Я уверен, что в нем есть дыры, но это кажется лучше, чем альтернативы.