esta pode ser uma questão trivial, mas: Visto que a estrutura de entidade ADO.NET rastreia automaticamente as alterações (em entidades geradas) e, portanto, mantém os valores originais, como posso reverter as alterações feitas nos objetos de entidade?
Eu tenho um formulário que permite ao usuário editar um conjunto de entidades "Cliente" em uma visão de grade.
Agora tenho dois botões "Aceitar" e "Reverter": se "Aceitar" for clicado, eu chamo Context.SaveChanges()
e os objetos alterados são gravados de volta no banco de dados. Se "Reverter" for clicado, gostaria que todos os objetos obtivessem seus valores de propriedade originais. Qual seria o código para isso?
obrigado
fonte
Context.Refresh()
é um contra-exemplo à sua afirmação de que não há operação de reversão? UsarRefresh()
parece uma abordagem melhor (ou seja, mais facilmente direcionado a entidades específicas) do que descartar o contexto e perder todas as alterações rastreadas.Consulte ChangeTracker de DbContext para itens sujos. Defina o estado dos itens excluídos como inalterado e os itens adicionados como desanexados. Para itens modificados, use os valores originais e defina os valores atuais da entrada. Por fim, defina o estado da entrada modificada como inalterado:
fonte
State
como EntityState.Unchanged substituirá todos os valoresOriginal Values
também, portanto, não há necessidade de chamar oSetValues
método.Accroding to MSDN :
Observe que reverter por meio da solicitação para o banco de dados tem algumas desvantagens:
fonte
Isso funcionou para mim:
Onde
item
está a entidade do cliente a ser revertida.fonte
Maneira fácil sem rastrear quaisquer alterações. Deve ser mais rápido do que olhar para todas as entidades.
fonte
Rollback
procedimento acima , o que o torna uma escolha muito melhor se alguém deseja reverter todo o estado do banco de dados. A reversão poderia escolher a cereja do bolo.50ms+0*n= 50ms
. O (n) significa que o desempenho é influenciado pelo número de objetos ... o desempenho é talvez2ms+0.5ms*n
... então abaixo de 96 objetos seria mais rápido, mas o tempo aumentaria linearmente com a quantidade de dados.Funcionou para mim No entanto, você deve recarregar seus dados do contexto para trazer os dados antigos. Fonte aqui
fonte
"Isso funcionou para mim:
Onde
item
está a entidade do cliente a ser revertida. "Eu fiz testes com ObjectContext.Refresh no SQL Azure e o "RefreshMode.StoreWins" dispara uma consulta no banco de dados para cada entidade e causa um vazamento de desempenho. Com base na documentação da Microsoft ():
ClientWins: as alterações de propriedade feitas em objetos no contexto do objeto não são substituídas por valores da fonte de dados. Na próxima chamada para SaveChanges, essas alterações são enviadas para a fonte de dados.
StoreWins: as alterações de propriedade feitas em objetos no contexto do objeto são substituídas por valores da fonte de dados.
ClientWins também não é uma boa ideia, porque disparar .SaveChanges irá comprometer as alterações "descartadas" na fonte de dados.
Ainda não sei qual é a melhor maneira, porque descartar o contexto e criar um novo causa uma exceção com a mensagem: "O provedor subjacente falhou ao abrir" quando tento executar qualquer consulta em um novo contexto criado.
Saudações,
Henrique Clausing
fonte
Quanto a mim, o melhor método para fazer isso é definir
EntityState.Unchanged
todas as entidades nas quais você deseja desfazer as alterações. Isso garante que as alterações sejam revertidas no FK e tenham uma sintaxe um pouco mais clara.fonte
Achei que isso estava funcionando bem no meu contexto:
Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);
fonte
DbContext.SaveChanges()
, mas não retornará os valores da entidade aos valores originais. E se o estado da entidade for modificado a partir de uma alteração posterior, possivelmente todas as modificações anteriores persistirão ao salvar?Este é um exemplo do que Mrnka está falando. O método a seguir substitui os valores atuais de uma entidade pelos valores originais e não chama o banco de dados. Fazemos isso usando a propriedade OriginalValues de DbEntityEntry e usamos a reflexão para definir valores de uma maneira genérica. (Funciona a partir do EntityFramework 5.0)
fonte
Estamos usando EF 4, com o contexto Legacy Object. Nenhuma das soluções acima respondeu a isso diretamente para mim - embora ela tenha respondido a longo prazo, me empurrando na direção certa.
Não podemos simplesmente descartar e reconstruir o contexto porque alguns dos objetos que temos pendurados na memória (maldito carregamento lento !!) ainda estão anexados ao contexto, mas têm filhos que ainda estão para ser carregados. Para esses casos, precisamos colocar tudo de volta aos valores originais sem martelar o banco de dados e sem interromper a conexão existente.
Abaixo está nossa solução para este mesmo problema:
Espero que isso ajude outros.
fonte
Algumas boas idéias acima, eu escolhi implementar ICloneable e um método de extensão simples.
Encontrado aqui: Como faço para clonar uma lista genérica em C #?
Para ser usado como:
Desta forma, consegui clonar minha lista de entidades de produto, aplicar um desconto a cada item e não ter que me preocupar em reverter nenhuma alteração na entidade original. Não há necessidade de falar com o DBContext e pedir uma atualização ou trabalhar com o ChangeTracker. Você pode dizer que não estou fazendo uso completo do EF6, mas esta é uma implementação muito boa e simples e evita um impacto no banco de dados. Não posso dizer se isso teve ou não um impacto no desempenho.
fonte