quinta-feira, 8 de abril de 2010

Cancelar alterações na entity (ou delta ou changeset)

Você já tentou criar um cadastro mestre-detalhe com o Entity Framework? Pois bem, eu estou tentando chegar lá...

Como eu venho de um background data-centric, onde datasets são a pattern mais utilizada para a) persistir dados em memória; b) manter changeset; c) prover dados para as telas, o trabalho de controlar a edição de objetos é bastante simples. Cancelar as alterações de um registro ou de um conjunto inteiro de registros é moleza. Isto se deve a uma outra estrutura conhecida como delta (ou ainda changeset), que mantém cada inclusão/edição/exclusão de dados. Para reverter as alterações em memória, basta limpar o buffer do registro corrente ou então limpar o delta.

No Entity Framework as coisas não são simples assim. Não importa se o projeto segue uma abordagem code-first, database-first ou model-first. Se fosse fácil haveria um método RevertChanges() ou na entidade ou no ObjectContext. Um CRUD fica complicado de se implementar ou no mínimo moroso, sem auxílio da camada de apresentação. Claro que isso tem um aspecto positivo, força o desenvolvedor a planejar um modelo de apresentação independente do modelo de dados. Mas voltemos ao assunto do post.

O cenário mais básico é reverter as edições em atributos escalares ou string, ou seja, todos exceto os relacionamentos com outras entidades. O ObjectStateManager armazena uma entrada para cada entidade no contexto, juntamente com os valores originais. Podemos copiar os valores originais novamente na entidade:

public static void RevertChangesSingleEntity(this ObjectContext db, EntityObject entity)
{
    // reverte alterações em propriedades escalares de uma entidade
    ObjectStateEntry ose;
    if (db.ObjectStateManager.TryGetObjectStateEntry(entity, out ose))
    {
        var org = ose.GetUpdatableOriginalValues();
        var props = ose.GetModifiedProperties();
        foreach (var prop in props)
        {
            var x = entity.GetType().GetProperty(prop);
            x.SetValue(entity, org.GetValue(org.GetOrdinal(prop)), null);
        }
        ose.AcceptChanges();
    }
}

Bom, então se bastam estas linhas de código, porque não está incluído no EF? Acho que o time responsável pelo framework não tem conhecimento preciso das necessidades de um cenário como este para um ORM...

(to be continued...)

Nenhum comentário:

Postar um comentário