none
EF com windows form RRS feed

  • Pergunta

  • Galera,

    Qual seria uma boa maneira de trabalhar com o EF usando windows forms?? eu começei um projeto deixando o context no MDI form e passo para os forms filhos esse mesmo contexto, ou seja, uso um contexto durante toda a execução do programa. Existe algum maneira melhor para fazer isso ou a microsoft orienta usar assim??

    Caso eu esteja fazendo certo, como fica o seguinte cenario... imagine que ao abrir o form "ListarClientes" e clicar na linha da grid passando o objeto da linha correspondente para o form "EditarCliente"... bom, eu faço um monte de edição no objeto, ai no final eu desisto das edições e cancelo a edição.. bom, ai que esta o problema, eu ja alterei diretamente no objeto e quando eu volto a listagem o objeto ja esta alterado, como faço para resolver esse problema?? 

    vlww


    Ozzyvegeta
    terça-feira, 13 de abril de 2010 22:57

Respostas

  • Olha nao sei se é a melhor forma... mas eu gosto de criar um contexto estatico no Program.... ja que Windows Forms é mono-usuario mesmo...
    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    terça-feira, 13 de abril de 2010 23:28
    Moderador
  • Olha ate tem... é que eu normalmente trabalho com o EF num WebService.. entao nao tenho esse tipo de problema... mas se nao me engando se vc fizer:

    context.Refresh(RefreshMode.ClientWins, entity);

    fora isso, da para adaptar algo sim... tipo to sem muito tempo de testar agora... mas da uma olhada nisso aqui e ve se te ajuda:

     public static void CancelCurrentChanges(this ObjectContext context, ref object entity) {
        var entry = context.ObjectStateManager.GetObjectStateEntry(entity);
        for (int i = 0; i < entry.OriginalValues.FieldCount; i++) {
            var name = entry.OriginalValues.GetName(i);
            var value = entry.OriginalValues.GetValue(i);

            var property = entity.GetType().GetProperty(name);
            if (property == null) continue;
            property.SetValue(entity, value, null);
        }
    }

    quinta-feira, 15 de abril de 2010 00:21
    Moderador
  • Alias... se for no 4.0 ja tem o metodo para isso:

    context.ObjectStateManager.GetObjectStateEntry(entidade).ApplyOriginalValues(entidade);


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    quinta-feira, 15 de abril de 2010 18:18
    Moderador
  • Entao... nos meus WS quando eu recebo a Entidade via paramentro no meu webmethod ela ja vem desattachada bunitinha como tem que ser e o Attach ____ numa boa... eu so do um:

    if (this.EntityState == System.Data.EntityState.Detached) context.Attach(this); para caso eu teje chamando o metodo internalmente ....

    mas enfim... volta a questao que ja falei noutro post aqui... EF é não ferramenta para sistema de altaperformance.... enquanto vc quiser escovar bites "nao indo desncessariamente ao banco" não é usando EF que vai fazer isso....

    como eu uso webservice... meu acesso a dados fica centrado em 1 unico servidor... que aguenta muito... entao nao esquento com quantidade de acessos ao BD...

    mesmo pq o Sql tem tanto poolings e caches internos... que nao perde performance em nada... mas enfim... eu gosto de ficar dando FirstOrDefault o tempo todo para verificar se o registro foi ou nao alterado por outro usuario antes de fazer qq processamento com a entidade q recebo no webmethod....


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    sexta-feira, 16 de abril de 2010 21:33
    Moderador

Todas as Respostas

  • Olha nao sei se é a melhor forma... mas eu gosto de criar um contexto estatico no Program.... ja que Windows Forms é mono-usuario mesmo...
    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    terça-feira, 13 de abril de 2010 23:28
    Moderador
  • entendo, bom, de uma forma ou de outra vc esta trabalhando da mesma forma que eu, inclusive tive a mesma conclusao por ser monousuario. Mais assim, será q isso eh a melhor maneira? e como vc trabalha quando precisa cancelar uma edição? o objeto foi alterado e eh preciso um "rollback" vamos se dizer assim para que o savechanges não o afete. ?

    eu to usando o metodo Refresh com o ENUM StoregWins para esse "RollBack", mais isso tem um custo de ir na base novamente apenas pq o cara clicou em "Cancelar". 


    Ozzyvegeta
    quarta-feira, 14 de abril de 2010 12:47
  • Entao... eu faço Rollback a moda antiga mesmo :)

    da uma olhada nisso aqui que eu faço para dar o AcceptAllChanges e dar um rollback em caso de Exception

            public static void CommitAllChanges(this ObjectContext context) {
                context.CommitAllChanges(IsolationLevel.Unspecified);
            }
            public static void CommitAllChanges(this ObjectContext context, IsolationLevel isolationLevel) {
                if (context.Connection.State != ConnectionState.Open)
                    context.Connection.Open();
    
                var transaction = context.Connection.BeginTransaction(isolationLevel);
                try {
                    context.AcceptAllChanges();
                    transaction.Commit();
                } catch {
                    transaction.Rollback();
                    throw;
                }
            }

     


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    quarta-feira, 14 de abril de 2010 19:28
    Moderador
  • ha entao.. quando eu disse "RollBack" foi um modo de dizer rsrs... eu quis dizer voltar os valores iniciais da entidade antes de ser editada pelo FORM... exemplos..

    Chamando o form de edição

    ----------------------------------

    var cxt = Program.GetContext()// Metodo static criado para recuperar o context unico.

    var cliente = cxt.ClienteSet.FirstOrDefault();

    var frmCliente = new frmCliente();

    frmCliente.ClienteEdit = cliente; // Esse propriedade seta o cliente para ser editado

    frmCliente.Init(); // Esse metodo init faz o binding dos valores para os campos e o logo show

    ----------------------------

    Metodo de Save do form de edição

    -------------------------------------------

    var cxt = Program.GetContext();

    cxt.SaveChanges(); // Até aqui tranquilo, faz o save e ja era...

     

    A questão é que estou trabalhando com aquela ferramenta de DataBinding do .net (esqueci de comentar isso antes), ou seja, ele afeta o objeto no momento que o cara digita (no on change de um textfield) , por exemplo. Ai quando eu faço um CANCEL o objeto ja foi afetado e nesse momento eu tenho um problema pq qualquer outro savechanges ocorrer vai fazer persistir essa alteração que foi CANCELADA.  Ai pensei, sera q não existe algum meio de voltar a entidade para os valores originais? Ai eu encontrei a solução de no metodo de cancel fazer um Refresh na entidade, porem dessa forma eu perco em performance por ter que ir na base. E detalhe, por causa apenas um CANCEL! :(... por isso veio o meu desconforto em usar dessa maneira e queria saber se alguem ja teve esse tipo de problema e conseguiu uma solução mais elegante que a minha. Eu até pensei em copiar os valores para outra entidade fora do contexto e trabalhar em cima dela, porem ai sai da ideia inicial dessa arquitetura.

    E a pergunta eh... sera que existe uma maneira padrão que a MS proproe quando opta por apenas um context em toda a aplicação para não persistir essas alterações que foram canceladas?

    []s

     



    Ozzyvegeta
    quarta-feira, 14 de abril de 2010 21:20
  • Olha ate tem... é que eu normalmente trabalho com o EF num WebService.. entao nao tenho esse tipo de problema... mas se nao me engando se vc fizer:

    context.Refresh(RefreshMode.ClientWins, entity);

    fora isso, da para adaptar algo sim... tipo to sem muito tempo de testar agora... mas da uma olhada nisso aqui e ve se te ajuda:

     public static void CancelCurrentChanges(this ObjectContext context, ref object entity) {
        var entry = context.ObjectStateManager.GetObjectStateEntry(entity);
        for (int i = 0; i < entry.OriginalValues.FieldCount; i++) {
            var name = entry.OriginalValues.GetName(i);
            var value = entry.OriginalValues.GetValue(i);

            var property = entity.GetType().GetProperty(name);
            if (property == null) continue;
            property.SetValue(entity, value, null);
        }
    }

    quinta-feira, 15 de abril de 2010 00:21
    Moderador
  • Olá...

    vou testar esse código... não sabia q o EF guardava os original values... ;)... hehhe

    vlwwww Rui


    Ozzyvegeta
    quinta-feira, 15 de abril de 2010 12:18
  • Alias... se for no 4.0 ja tem o metodo para isso:

    context.ObjectStateManager.GetObjectStateEntry(entidade).ApplyOriginalValues(entidade);


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    quinta-feira, 15 de abril de 2010 18:18
    Moderador
  • poxa..bacana isso... agora vai fica melhro msm...

    mais cara, vc trabalha com o EF2 correto? vc disse q deixa td num WS certo, mais como q fica para atualizar suas entidades que estao fora do contexto??aquela velha questao do attach que n funciona miuto bem ;(... tem como contornar isso de alguma forma mais elegante... oq eu faço eh copiar a entity key e logo as propriedades para assim fazer o update sem precisa ir na base ...

     

     


    Ozzyvegeta
    sexta-feira, 16 de abril de 2010 02:16
  • Entao... nos meus WS quando eu recebo a Entidade via paramentro no meu webmethod ela ja vem desattachada bunitinha como tem que ser e o Attach ____ numa boa... eu so do um:

    if (this.EntityState == System.Data.EntityState.Detached) context.Attach(this); para caso eu teje chamando o metodo internalmente ....

    mas enfim... volta a questao que ja falei noutro post aqui... EF é não ferramenta para sistema de altaperformance.... enquanto vc quiser escovar bites "nao indo desncessariamente ao banco" não é usando EF que vai fazer isso....

    como eu uso webservice... meu acesso a dados fica centrado em 1 unico servidor... que aguenta muito... entao nao esquento com quantidade de acessos ao BD...

    mesmo pq o Sql tem tanto poolings e caches internos... que nao perde performance em nada... mas enfim... eu gosto de ficar dando FirstOrDefault o tempo todo para verificar se o registro foi ou nao alterado por outro usuario antes de fazer qq processamento com a entidade q recebo no webmethod....


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    sexta-feira, 16 de abril de 2010 21:33
    Moderador