EntityFramework: обновить отдельное поле с отсоединенным объектом - PullRequest
3 голосов
/ 31 августа 2011

В отличие от обычного, у меня есть код, который на самом деле работает, но мне интересно, если это единственный (или лучший подход).

Основная идея заключается в том, что у меня есть существующее приложение, которое вручную переносит слой данных в Entity Framework.В качестве компромисса, чтобы минимизировать изменения кода, я работаю с существующими методами, которые, как правило, используют более автономный подход.Например, у меня есть много вещей, подобных этому:

UpdateNote(int noteId, string note)

Мне кажется, у меня есть метод, который работает для этого типа обновления без необходимости повторной выборки:

var context = new MyEntities();
context.Configuration.ValidateOnSaveEnabled = false;
var note = new Model.Note{ Id = noteId, Note = ""};
context.Notes.Attach(note);
note.Note = "Some Note";
context.SaveChanges();

Этонемного некрасиво (хотя и достаточно кратко), поэтому я хотел бы знать, есть ли лучший подход для использования с EF?Есть ли недостатки этого метода, кроме потери встроенной проверки?

Это шаблон, который будет использоваться во всем моем приложении.

Ответы [ 2 ]

3 голосов
/ 31 августа 2011

Следующий метод расширения для DbContext - это подход, который позволит избежать инициализации ваших сущностей некоторыми значениями, отличными от значений, которые вы хотите изменить.

public static class EFExtensions
{
    public static void MarkAsModified(this DbContext context, object entity,
        params string[] properties)
    {
        foreach (var property in properties)
            context.Entry(entity).Property(property).IsModified = true;
    }
}

Затем вы можете использовать его следующим образом:

var context = new MyEntities();
context.Configuration.ValidateOnSaveEnabled = false;

var note = new Model.Note { Id = noteId }; // only key properties required to set

note.Note = "Some Note";
note.SomeOtherProperty = 1234;
note.AndAnotherProperty = "XYZ";

context.Notes.Attach(note);
context.MarkAsModified(note, "Note", "SomeOtherProperty" , "AndAnotherProperty");

context.SaveChanges();

Примечание. Это работает только для скалярных, а не навигационных свойств.

Помимо проверки, я могу представитьчто этот подход проблематичен для правильной проверки параллелизма.

Редактировать

Согласно приведенному ниже комментарию @Adam Tuliper, параллелизм, вероятно, не является проблемой, потому что проверка параллелизма пропускается, когдаобъект присоединяется к контексту вручную (без чтения его из базы данных) и помечается как измененный для отправки команды UPDATE в базу данных.Он просто переписывает последнюю версию в БД.Спасибо Адаму за то, что указал на это!

2 голосов
/ 01 сентября 2011

См. Следующий код, который я использую, чтобы легко прикрепить отключенный объект обратно к графику, предполагая, что мы сейчас его сохраним.


public static class EntityFrameworkExtensions
{
    /// <summary>
    /// This class allows you to attach an entity.
    /// For instance, a controller method Edit(Customer customer)
    /// using ctx.AttachAsModified(customer); 
    /// ctx.SaveChanges();
    /// allows you to easily reattach this item for udpating.
    /// Credit goes to: http://geekswithblogs.net/michelotti/archive/2009/11/27/attaching-modified-entities-in-ef-4.aspx
    /// </summary>
    public static void AttachAsModified<T>(this ObjectSet<T> objectSet, T entity) where T : class
    {
        objectSet.Attach(entity);
        objectSet.Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    }

    /// <summary>
    /// This marks an item for deletion, but does not currently mark child objects (relationships).
    /// For those cases you must query the object, include the relationships, and then delete.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="objectSet"></param>
    /// <param name="entity"></param>
    public static void AttachAsDeleted<T>(this ObjectSet<T> objectSet, T entity) where T : class
    {
        objectSet.Attach(entity);
        objectSet.Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Deleted);
    }

    public static void AttachAllAsModified<T>(this ObjectSet<T> objectSet, IEnumerable<T> entities) where T : class
    {
        foreach (var item in entities)
        {
            objectSet.Attach(item);
            objectSet.Context.ObjectStateManager.ChangeObjectState(item, EntityState.Modified);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...