sexta-feira, 9 de abril de 2010

Cancelar alterações em associações

O método RevertChangesSingleEntity() tem suas restrições, por exemplo não trata o caso da entity ter sido adicionada. Este cenário deve ser revertido com o detach da entity de seu context, embora a entidade continuará a existir fora dele. Importante frisar que o método ObjectContext.Detach() atua em uma única entity por vez, e desintegra o grafo que participava, pois não pode haver parte do grafo no contexto e outra parte fora. Pode pensar nisso como o gato de Schrödinger. Isto significa que o se eu tiver um Pedido e uma coleção ItemDoPedido adicionados no contexto, para reverter esta inclusão é preciso detach cada objeto individualmente. Entretanto o Pedido ficaria desconectado de seus ítens. Outra característica do detach é que a entrada (classe ObjectStateEntry) no change tracker permanece com a EntityKey e o State anterior, porém a propriedade Entity será nula pois foi desconectada.

Uma outra maneira de parar o change tracking dos objeto é executar IEntityWithChangeTracker.SetChangeTracker() passando null como o único parâmetro. Isto remove o IEntityChangeTracker que monitora e registra as alterações no objeto. A vantagem disso é que o grafo permanece intacto, e a desvantagem é que parte do grafo continua registrando as alterações e parte não mais.

Acontece que adicionar/deletar uma entidade em um relacionamento implica em manter outras entradas no ObjectStateManager referente aos relacionamentos, como podemos ver na imagem a seguir.



Segue código para tratar a reversão das associações:

public static void RevertChanges(this ObjectContext db)


{
    foreach (var ose in db.ObjectStateManager.GetObjectStateEntries(EntityState.Added))
        ose.Delete();
    foreach (var ose in db.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
    {
        if (!ose.IsRelationship)
        {
            var org = ose.GetUpdatableOriginalValues();
            var props = ose.GetModifiedProperties();
            foreach (var prop in props)
            {
                var x = ose.Entity.GetType().GetProperty(prop);
                x.SetValue(ose.Entity, org.GetValue(org.GetOrdinal(prop)), null);
            }
        }
    }
    foreach (var ose in db.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted))
        if (!ose.IsRelationship)
            ose.ChangeState(EntityState.Unchanged);


    db.AcceptAllChanges();
}

(to be continued...)

Nenhum comentário:

Postar um comentário