CodeTip #3 – Aktualizacja property w Entity Framework

Hej!

często w systemach, które implementujemy zachodzi potrzeba aktualizacji jednej kolumny w bazie danych. Przykładowo, tabela User może posiadać flagę IsLocked, która będzie informowała o tym, czy użytkownik jest zablokowany. Chcąc zaimplementować metodę blokującą delikwenta, część pomyśli o następującej implementacji:


public async Task LockUserAsync(string id)
{
    var context = new DbContext();
    var user = context.Users.SingleOrDefault(u => u.Id == id);

    user.IsLocked = true;

    context.Entry(user).State = EntityState.Modified;

    await context.SaveChangesAsync();
}

 

Poniżej zapytania jakie zostały wysłane do bazy danych:

 

sample1

 

Kod działa i spełnia swoje założenia. Problem polega na tym, że zmiana jednej flagi wymusiła na nas uprzednie pobranie danych użytkownika. Cała operacja potrzebowała zatem dwóch round tripów do bazy danych. Z punktu widzenia SQL, jest to trochę dziwne. Skoro posiadamy identyfikator użytkownika oraz nową wartość kolumny to dlaczego nie możemy od razu przejść do wykonania polecenia UPDATE? Otóż możemy 😉

 


public async Task LockUserAsync(string id)
{
    var user = new UserEntity { Id = id, IsLocked = true };

    var context = new DbContext();

    context.Users.Attach(user);

    var entry = context.Entry(user);

    entry.Property(u => u.IsLocked).IsModified = true;</pre>
<pre>    await context.SaveChangesAsync();</pre>
<pre>} 

 

Co właściwie zrobiliśmy? Po pierwsze utworzyliśmy obiekt encji użytkownika, uzupełniając przy tym  identyfikator oraz flagę IsLocked. Należy pamiętać, że nasz utworzony obiekt musi posiadać właściwość, która jednoznacznie określi jej odpowiednik w bazie danych. Z tego względu najlepszym rozwiązaniem jest Id, a nie np. nazwisko. Następnie do naszego kontekstu bazodanowego metodą Attach dołączamy obiekt, po czym określamy które pole zostało zaktualizowane. Zobaczmy, jak wygląda rezultat naszych działań:

 

sample2

 

Teraz jest ok! Zbędny round trip został wyeliminowany, a my  jesteśmy hepi 😉 Warto oczywiście pokusić się o jakieś opakowanie kodu w metodę i umieszczenie jej np. w repozytorium. Poniżej przykładowa implementacja:

 


public void UpdateProperty<TProperty>(TEntity entity, Expression<Func<TEntity, TProperty>> propertySelector)
{
    _context.Set<TEntity>().Attach(entity);

    var entry = _context.Entry(entity);

    entry.Property(propertySelector).IsModified = true;
}

 

To chyba wszystko. Niebawem pojawi się kolejny wpis konkursowy (najprawdopodobniej w weekend). Przypominam o śledzeniu mojego twittera, gdzie znajdziecie najnowsze wpisy i ciekawostki ze świata IT.

Cześć !

You may also like...