none
Camada de Acesso a Dados (DAL), Linq, Entity Framework, SQL Server RRS feed

  • Pergunta

  • Boas.

     

    Estamos desenvolvendo um projeto utilizando C#, WPF, LINQ e Entity Framework. Dividimos o projeto em 3. Um projeto WPF com a interface, uma Class Library com o Entity Framework e uma Class Library com o acesso a dados (DAL) utilizando LINQ.

    Pergunta: Estou certo em dividir o projeto em 3 projetos dessa maneira?

     

    Eu tenho o seguinte código para abrir a conexão com a minha base de dados MS-SQL Server 2005:

    private static SisWebClasses.siswebEntities dm = new SisWebClasses.siswebEntities();

     

    Pergunta: Onde eu devo abrir essa conexão? Eu devo abri-la apenas no Projeto DAL? Como eu faço isso apenas uma vez enquanto a aplicação principal estiver rodando?

     

    Ao executar o projeto, eu abro uma tela e exibo os dados num DataGrid da Xceed:

     

    dgSetor.ItemsSource = SetorDAL.SetorSelecionarTotal();

     

    E tenho o comando LINQ que retorna os Dados:

     

    public static System.Linq.IQueryable SetorSelecionarTotal()

    {

    return (from c in dm.tbSetor

    select new { c.IdSetor, c.Setor, c.Situacao });

    }

     

    Até aqui tudo ocorre bem. A seleção é realizada quantas vezes eu entrar e sair da tela sem erros. Quando vou salvar uma alteração no entanto ocorre o seguinte erro:

     

    An error occurred while starting a transaction on the provider connection. See the inner exception for details.

     

    {"New transaction is not allowed because there are other threads running in the session."}

     

    O método da Alteração:

    public static void SetorAlterar(int prIdSelecionado, string prSetor, bool prSituacao)

    {

    tbSetorTabela = (from c in dm.tbSetor

    where c.IdSetor == prIdSelecionado

    select c).First();

    tbSetorTabela.Setor = prSetor;

    tbSetorTabela.Situacao = prSituacao;

    dm.SaveChanges();

    }

     

    O mesmo erro ocorre na Inclusão!

     

    Alguém tem idéia de como resolvo tudo isso? rsrs

     

    Obrigado desde já pela ajuda!

     

    Leonardo.

    terça-feira, 2 de dezembro de 2008 13:32

Todas as Respostas

  • Boas pessoal.

     

    Recebi um e-mail do Israel Aece sobre o assunto com dois links muito interessantes:

     

    http://blogs.objectsharp.com/cs/blogs/barry/archive/2008/04/27/the-entity-framework-vs-the-data-access-layer-part-0-introduction.aspx

     

    http://blogs.objectsharp.com/cs/blogs/barry/archive/2008/05/06/the-entity-framework-vs-the-data-access-layer-part-1-the-ef-as-a-dal.aspx

     

    No entanto, não consegui ainda resolver o problema e o erro continua ao chamar o famigerado SaveChanges();

     

    Será que mais alguém pode nos ajudar?

     

    Obrigado!

    Leo

     

     

    quarta-feira, 3 de dezembro de 2008 15:46
  • Cara eu ainda não utilizei o EF, estou usando o LINQ TO SQL e ainda não parei para analisa as particularidades. Por isso vou lhe passar um link com alguns projetos em LINQ TO SQL, derepente da uma clareada nas idéias.

     

    http://www.codeplex.com/site/search?ProjectSearchText=linq%20tier

     

     

    quinta-feira, 4 de dezembro de 2008 01:16
  • Obrigado pela atenção Walber.

    Eu nunca usei o LINQ TO SQL por ter escolhido justamente o LINQ TO ENTITIES com o Entity Framework.

    De qualquer maneira, após muita pesquisa cheguei a algumas conclusões.

    O Entity Framework ainda esta engatinhando e temos pouca documentação em português com exemplos de utilização no mundo real. Exemplo que o pessoal copia de wizards bem simples (que até eu consigo fazer com toda a minha inexperiencia no assunto), isso você acha bastante. Mas coisas que usaremos de verdade no dia-a-dia esquece. Só acho artigo encheção de linguiça! Um parecido com o outro.

     

    Um blog muito bom http://www.thedatafarm.com/blog/ de Julie Lerman tem me ajudado muito.

     

    Resumindo eu descobri que quando você divide o projeto e coloca a Interface de um lado e o Entity Framework de outro lado numa class library, simplesmente o SaveChanges() não funciona mais. Para que ele funcione, é necessário codificar algumas coisas que eu ainda estou testando, mas que eu acho simplesmente um saco. Cadê a praticidade que o modelo oferece? A produtividade, rapidez?

     

    Agora, se você fizer um projeto unico com a UI e o EF juntos, tudo funciona. Mas se eu quero utilizar o modelo tanto para uma aplicação WPF quanto para um site ASP.NET eu tenho q fazer duas vezes a mesma coisa? Acho que não né?

     

    Depois desse post desabafo vamos continuar testando e pesquisando até achar uma alternativa produtiva ou abandonar por enquanto o Entity Framework.

     

    Leonardo.

    quinta-feira, 4 de dezembro de 2008 16:31
  • A gente teve uma discursao em outro post sobre usar ou nao o DataContext em um metodo estatico....

     

    realmente eu fazia assim e tive uma serie de problemas.... tenta criar uma nova instancia sempre dentro do metodo e liberar ao final e ve se funciona...

     

    Code Snippet

    public static void SetorAlterar(int prIdSelecionado, string prSetor, bool prSituacao)

    {

    using (var dm = new SisWebClasses.siswebEntities()) {

    tbSetorTabela = (from c in dm.tbSetor

    where c.IdSetor == prIdSelecionado

    select c).First();

    tbSetorTabela.Setor = prSetor;

    tbSetorTabela.Situacao = prSituacao;

    dm.SaveChanges();

    }

    }

     

     

    sexta-feira, 12 de dezembro de 2008 17:53
    Moderador
  • Ola Leonardo, ainda esta por ai?...Estou começando os estudos em um projeto parecido, com este tempo que passou tem alguma orientação...Quero usar o EF para ter flexibilidade de banco....
    []s
    t+
    segunda-feira, 27 de julho de 2009 22:26
  • Leonardo.

    Estes métodos não deveriam ser Estáticos, imagina se utilizarem o serviço ao mesmo tempo? ficará uma confusão de informações. Acabei de finalizar um projeto que utiliza WCF e garanto que o uso de métodos estáticos trazem muitos problemas quando utilizados incorretamente.

    Quando você está utilizando um método estático:
    private static SisWebClasses.siswebEntities dm = new SisWebClasses.siswebEntities();

    e faz isso

    using (var dm = new SisWebClasses.siswebEntities())

    O compilador está entendendo que fechou a conexão e "matou" o objeto da memória (Dispose) ao sair do using, então ele se perde, quando utiliza o SaveChanges().


    Minato alexandre.minato@hotmail.com
    quinta-feira, 6 de agosto de 2009 02:43
  • Em um projeto na empresa que trabalho, usei EF, e para criar a conexão eu utilizo uma classe Singleton:

    class DB
        {
            private static DAL.ADM.EmpresaEntities db;
    
            private DB()
            {
                
            }
    
            public static DAL.ADM.EmpresaEntities getConnection() 
    { if (db == null) { db = new DAL.ADM.EmpresaEntities();
    } return db; } }
    Alexandre, você aconselha fazer assim? ou teria alguma sugestão. Como todo mundo aqui, estou iniciando meus estudos no EF.

    Obrigado.
    segunda-feira, 10 de agosto de 2009 12:57
  • Leonardo, estou com o mesmo problema, o SaveChanges nao funciona.

    O que fazer?

    Elton de Lima Ribeiro
    segunda-feira, 7 de dezembro de 2009 17:25
  • ae galera..sei q o post eh antigo, porem acho que devemos reabrir essa questão.

    Bom, meus conhecimentos com EF são intermediarios.. para trabalhar desconectado, depois de tanta pesquisa, eu conclui que a melhor forma é criar uma instancia e copiar os dados antes do SaveChanges()... para o update uma forma legal que vi é criar um entity key.. assim n precisa ir até a base para fazer o update...

    bom, foi isso oq consegui até agora pra trampa desconectado..fiz um projeto grande com linq to sql dessa msm forma... usei metodos estaticos para as classes de BO... não gostei muito dessa pratica, mais enfim, td da certo, porem penso q devo ter saido da teoria em alguns momentos... mais td bem...

    outra coisa... attach e dettach não funfa nem pro LINQ2SQL e muito menos pro EF... isso é mito...

    vlww


    Ozzyvegeta
    quarta-feira, 17 de março de 2010 22:40
  • Então Pessoal,

     

    Eu já usei o Entity Framework e por experiência própria notei que:

     

    1) Nunca se usa métodos estáticos guardar o DataContext. Embora possa ser mais cômodo em alguns casos, para aplicações web na prática não funciona. Fica muito mais caro controlar a concorrência do acesso a dados. E depois, quando se tem 10 objetos na memória, eu salvo com SaveChanges uns 4, não tem como garantir que o controlador de alterações do EF reconhecerá esses objetos como alterados.

    2) Compensa sempre criar um DataContext com o bloco using, realizar o máximo de operações no bloco, trabalhar com os dados e depois fechar a conexão com o banco. Com isso você consegue garantir que todas as transações aconteceram quando você realmente quis.

    3) NO VS2010 grande parte destes problemas são resolvidos e é possível trabalhar tranquilamente com contextos, atachando, criando, modificando e excluindo os dados de maneira otimizada.


    Mário Correia de Meyrelles e Costa
    www.accendis.com.br
    www.twitter.com/accendis

    quinta-feira, 25 de março de 2010 13:39
  • Concordo com o Mário... trabalhei da mesma forma com o EF. Sempre com using.

    Cara..estou muito ansioso pra trabalhar com o 2010... vc tem noção d quando q vai lançar??

     


    Ozzyvegeta
    quinta-feira, 25 de março de 2010 14:17
  • Ozzy... o Detach do EF ta funcionando legal aqui.... o Attach ainda nao eh 100%, mas nesses casos eu to usando o GetObjectByKey do ObjectContext que vem me funcionando muito bem....
    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    quinta-feira, 25 de março de 2010 16:32
    Moderador
  • Olá Ozzy e Rui,

    Eu tive também problemas com essa parte do attach e detach, pq na prática, acontece 2 coisas:

    1) O objeto está em outro ObjectContext

    2) Atachamos o objeto e não altera nada.

     

    No VS2010 tem um esquema para atachar objetos modificados de forma bem bacana:

     

    protected virtual void SaveBooks(List<Livro> livros)
            {
                try
                {
                    using (AirbooksEntities entities = new AirbooksEntities())
                    {
                        foreach (Livro item in livros)
                        {
                            entities.Attach(item);
                            entities.ObjectStateManager.ChangeObjectState(item, System.Data.EntityState.Modified);
                        }
                        entities.SaveChanges(System.Data.Objects.SaveOptions.DetectChangesBeforeSave);
                    }
                    if (SaveCompleted != null)
                    {
                        SaveCompleted(livros.Count);
                    }
                }
                catch (Exception ex)
                {
                    if (SaveFailed != null)
                    {
                        SaveFailed(ex.ToString());
                    }
                }
                
            }
    

    O segredo tá no ObjectStateManager, que permite anexar ao contexto os objetos marcando-os como Modified.

    Neste exemplo eu amarrei uns eventos customizados para que eu pudese ver o andamento do processamento dos dados. Mas claro que não é necessário para o caso geral.

    Atenciosamente,

    Mário


    Mário Correia de Meyrelles e Costa
    www.accendis.com.br
    www.twitter.com/accendis

    sexta-feira, 26 de março de 2010 15:30
  • ah... entao o attach nao é para mudar nada mesmo... para isso tem o ApplyPropetyChanges... No caso de Entities Attachadas, descobri q usando o GetObjectByKey ele funciona :P

    public static bool AttachWithChanges(this ObjectContext context, EntityObject entity) {
        if (entity.EntityKey == null) return false;
    
        switch (entity.EntityState) {
            case System.Data.EntityState.Added:
                context.AddObject(entity.EntityKey.EntitySetName, entity);
                return true;                
            case System.Data.EntityState.Detached:
                context.Attach(entity);
                return true;                
            case System.Data.EntityState.Modified:
                context.ApplyPropertyChanges(entity.EntityKey.EntitySetName, entity);
                return true;
            case System.Data.EntityState.Unchanged:
                entity = (EntityObject)context.GetObjectByKey(entity.EntityKey);
                return entity != null;
            case System.Data.EntityState.Deleted:
            default:
                return false;                    
        }           
    }

    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    sexta-feira, 26 de março de 2010 21:24
    Moderador
  • Opa... vejo que alguams coisas parecem estar solucionadas nessa nova versão... quando que sai esse novo VS??

     

     


    Ozzyvegeta
    segunda-feira, 29 de março de 2010 11:47
  •  Ozzy, da ultima vez q vi ia ser em abril já...

     

    mas o codigo q eu postei é em 3.5 mesmo :P


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    terça-feira, 30 de março de 2010 00:21
    Moderador
  • Certo... mais esse tal de GetObjectByKey não ajuda muito pq o cara tem q ir na base recarregar a entidade sendo que ela ja carregada...eh esse tipo de Attach que gostaria que funcionasse saca... pra mim isso não eh attach... eh loadbyid ... mais enfim... pra mim o certo seria ele anexar uma entidade que venha ou não de outro context... ...
    Ozzyvegeta
    terça-feira, 30 de março de 2010 11:43
  • Entao.... vamos pensar mais afundo

    é muito provavel que vc tenha uma entidade em memoria, que pode se bobiar ficar ativa por dias... (se por exemplo ficar em no Application do website) enquato ela esta sendo alterada e muitas veses excluido por outros usuarios do sistema...

    Simplesmente anexar (attachar) a entidade, sem fazer um verificação antes na base para saber se o registro relamente esta la ainda.. ou se foi alterado.. enfim.. vc prescisa comparar o registro com os dados da base por uma questao de integridade de dados... nao da para fugir muito disso...

    Por isso que o Attach "não funciona", ele pode nao fazer a verificação na hora... mas quando vc da o SaveChanges.. ele vai fazer a consulta do mesmo jeito .... é algo que não tem como fugir...

    pessoalmente prefiro fazer o controle na mão... se o registro for inconsistente eu ja aborto o processo de cara e nao perco um tempo fazendo todos os calculos so para no final informa q o produto q ele selecionou ja foi excluido por exemplo...


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    terça-feira, 30 de março de 2010 21:47
    Moderador
  • entendo que ele "força" ha essa utilização, porem ainda acho que o attach teria que ser mais controlavel nesse ponto... não acho legal carregar uma entidade que muitas vezes é imensa apenas para fazer updates em duas colunas... toda hora ir na base é complicado... alem do mais, para mim deletar é preciso o mesmo procedimento... pra que buscar a entidade se vou deleta-la?? saca... o mundo que ele espera é algo aonde o context seja unico...porem num cenario web as coisas complicam.. manter um singleton do context não ____... fazer um context por session tb eh complicado... ao meu ver um attach simples resolveria tdoa a situação...

     


    Ozzyvegeta
    quarta-feira, 31 de março de 2010 04:26
  • bem ca entre nos... Frameworks de "Objetificacao" (na falta de um termo melhor)  de BD nao significa otimizacao de codigo... (seja Linq, Hibernate e etc)

    A vantagem é trabalhar com o banco como se ele fosse "orientado a objeto", porem é um tipo de gambiarra ja que a estrutura do mesmo nao suporta esse tipo de logica...

    Se o seu sistema requer muito um acesso de alta performance no seu banco (de muita alta mesmo... ) ai nao tem jeito.. eh fazer a query na mao e abrir mao desse tipo de comodidade...

    Agora eu trabalho com bases de dados na medida de centena de milhares de linhas... e nao vejo absolutamente problema nenhum em fazer dezenas de queries para ser sincero... mesmo pq os kernels do servidor nao passam de 15% mesmo em horario de pico...


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    quarta-feira, 31 de março de 2010 23:20
    Moderador
  • Cara... discordo... pra mim isso é super relevante independente do tamanho do sistema... quando passa dos 100 mil o negocio fica complicado... tive esse problema com o linq to sql... abandonei essa ideia de carregar a entidade para fazer update ou delete sendo que isso é desncessario... se é desnecessário entao pq fazer? td bem, no meu caso era desnecessário, mais se existe um que é entao que exista alguma opção para isso... ou seja, um attach que funcione de fato... era simples isso... adione um parametro nele.. sei lah.. qualquer coisa... 
    Ozzyvegeta
    quinta-feira, 1 de abril de 2010 15:01
  • Ah... ai eu discordo, framework tem que seguir uma metodologia... se for da asas as "excessoes" vai ser um problema... alias.. o tem ApplyPropertiesChanges para fazer o update, attach não é para isso... e se vc quer so attachar, entao use o Dettach antes... os metodos estao la... é questao de como vc usa eles...

     


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    quinta-feira, 1 de abril de 2010 16:49
    Moderador
  • cara... quando digo isso estou pensando num cenario com uma entidade complexa... com uma hierarquia grande, 1x1, 1xN ... imagina buscar a entidade para fazer um update de um campo ??? isso não pode ser considerado normal... e quando eu falo que o attach/dettach não funciona é exatamente nesse sentido... o dettach soh remove a entidade primaria do context e não seus filhos... mais até ai td bem, ta certo... o problema é o attach que deveria não ligar para isso, ou clonar a entidade, sei lah... eh uma sinuca de bico...
    Ozzyvegeta
    quinta-feira, 1 de abril de 2010 17:28
  • Sim mas é o que eu falei... são os males de força uma Base de dados a trabalhar com O.O. ela não é feita para isso...

    Mas os selects não sao tao pesados assim com uma boa organização de indeces e com o uso de cache do proprio SQL Server

    Eu trabalho com sistemas grandes... muito grandes... e não tenho problemas de performance mesmo tirando um absurdo de selects por segundo


    What would Brian Boitano do ?
    ((2B || !2B) is Question) ?
    quinta-feira, 1 de abril de 2010 21:29
    Moderador