none
Como usar update sem precisar fazer um select primeiro? RRS feed

  • Pergunta

  • Olá pessoal,

    Sou iniciante com LINQ. Existe alguma maneira de usar update sem ter que fazer um select antes para obter o resgistro?

    Grato,


    Duan Brito - Analista de Sistemas/Programador
    segunda-feira, 10 de outubro de 2011 20:33

Respostas

  • Olá Duan,

    Sim, o Attach é uma boa prática e tem uma performance excelente.
    Ele evita que vc tenha de fazer o select na base de dados para obter uma instância vinculada ao banco de dados, e tenha de fazer o "de/para" de sua instância para a instância vinda do banco de dados.

    O único detalhe importante é que vc precisa ter a propriedade correspondente a sua primary key valorizada, caso a mesma contenha o valor ZERO, então o Attach irá fazer um INSERT ao invés de um UPDATE.

    Segue exemplo:

    internal class BdDataContext : DataContext
    {
        private Table<Arquivo> _arquivosRelacionados;
    
        public BdDataContext(string connectionString)
            : base(connectionString)
        {
    
        }
    
        public BdDataContext(IDbConnection connection)
            : base(connection)
        {
    
        }
    
        public Table<Arquivo> Arquivos
        {
            get
            {
                if (this._arquivosRelacionados == null)
                    this._arquivosRelacionados = this.GetTable<Arquivo>();
    
                return this._arquivosRelacionados;
            }
        }
    }
        
    public void Salvar(Arquivo arquivo)
    {
        BdDataContext dataContext = null;
        
        using (dataContext = new BdDataContext("connection string"))
        {
            if (arquivo.Id == 0)
            {
                dataContext.Arquivos.InsertOnSubmit(arquivo);
            }
            else
            {
                Arquivo clone = null;
                clone = (Arquivo)arquivo.Clone();            
                dataContext.Arquivos.Attach(clone, true);           
            }
    
            dataContext.SubmitChanges();
        }
    }
    


    Obs.: Observer que minha classe Arquivo implementa a interface ICloneable, isso é necessário pois, caso a instância do objeto já esteja atachada ao data context (devido ao cache interno do LINQ) então é preciso que vc utilize uma instância não atachada para fazer o Attach. A implementação dessa interface é fácil e deve ser algo do tipo:

    class Arquivo : ICloneable
    {
        public int Id { get; set; }
    
        public string Name { get; set; }
    
        public string Url { get; set; }
    
        public object Clone()
        {
            Arquivo clone = new Arquivo();
            clone.Id = this.Id;
            clone.Name = this.Name;
            clone.Url = this.Url;
        }
    }
    


    Lembrado que tudo isso está incluso no namespace System.Data.Linq e esteja disponível no Framework 4.0

    []s!

    Referência:
    http://msdn.microsoft.com/en-us/library/bb548978.aspx


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    • Marcado como Resposta Duan Brito terça-feira, 11 de outubro de 2011 11:59
    terça-feira, 11 de outubro de 2011 11:56
    Moderador

Todas as Respostas

  • Olá Duan,

    Sim, existe. Para tanto vc deve ter seu objeto do modelo com os dado necessários, e utilizar o método Attach (contido no seu data context), para atachar seu objeto ao banco de dados, e arremeter as atualizações.

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    terça-feira, 11 de outubro de 2011 03:10
    Moderador
  • Olá Fernando?

    Você poderia falar rapidamente sobre o Attach? Por exemplo, se é uma boa prática, se é bom em relação a performance e etc...

     

    Grato,


    Duan Brito - Analista de Sistemas/Programador
    terça-feira, 11 de outubro de 2011 11:38
  • Olá Duan,

    Sim, o Attach é uma boa prática e tem uma performance excelente.
    Ele evita que vc tenha de fazer o select na base de dados para obter uma instância vinculada ao banco de dados, e tenha de fazer o "de/para" de sua instância para a instância vinda do banco de dados.

    O único detalhe importante é que vc precisa ter a propriedade correspondente a sua primary key valorizada, caso a mesma contenha o valor ZERO, então o Attach irá fazer um INSERT ao invés de um UPDATE.

    Segue exemplo:

    internal class BdDataContext : DataContext
    {
        private Table<Arquivo> _arquivosRelacionados;
    
        public BdDataContext(string connectionString)
            : base(connectionString)
        {
    
        }
    
        public BdDataContext(IDbConnection connection)
            : base(connection)
        {
    
        }
    
        public Table<Arquivo> Arquivos
        {
            get
            {
                if (this._arquivosRelacionados == null)
                    this._arquivosRelacionados = this.GetTable<Arquivo>();
    
                return this._arquivosRelacionados;
            }
        }
    }
        
    public void Salvar(Arquivo arquivo)
    {
        BdDataContext dataContext = null;
        
        using (dataContext = new BdDataContext("connection string"))
        {
            if (arquivo.Id == 0)
            {
                dataContext.Arquivos.InsertOnSubmit(arquivo);
            }
            else
            {
                Arquivo clone = null;
                clone = (Arquivo)arquivo.Clone();            
                dataContext.Arquivos.Attach(clone, true);           
            }
    
            dataContext.SubmitChanges();
        }
    }
    


    Obs.: Observer que minha classe Arquivo implementa a interface ICloneable, isso é necessário pois, caso a instância do objeto já esteja atachada ao data context (devido ao cache interno do LINQ) então é preciso que vc utilize uma instância não atachada para fazer o Attach. A implementação dessa interface é fácil e deve ser algo do tipo:

    class Arquivo : ICloneable
    {
        public int Id { get; set; }
    
        public string Name { get; set; }
    
        public string Url { get; set; }
    
        public object Clone()
        {
            Arquivo clone = new Arquivo();
            clone.Id = this.Id;
            clone.Name = this.Name;
            clone.Url = this.Url;
        }
    }
    


    Lembrado que tudo isso está incluso no namespace System.Data.Linq e esteja disponível no Framework 4.0

    []s!

    Referência:
    http://msdn.microsoft.com/en-us/library/bb548978.aspx


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    • Marcado como Resposta Duan Brito terça-feira, 11 de outubro de 2011 11:59
    terça-feira, 11 de outubro de 2011 11:56
    Moderador
  • Olá Fernando,

    Muito obrigado pelos esclarecimentos.

    At.


    Duan Brito - Analista de Sistemas/Programador
    terça-feira, 11 de outubro de 2011 11:59
  • Olá Duan =]

    Havia dito que o Attach estava disponível no Framework 4.0, mas não... ele também estádiponível no Framework 3.5

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    terça-feira, 11 de outubro de 2011 12:04
    Moderador
  • Boa tarde Fernando..

    Tentei fazer isso no EF4.1 e o Attach não está disponível

    No EF4 está disponível.

    Pq será q não tem no EF4.1??

    quarta-feira, 30 de novembro de 2011 18:46
  • Oi Lion,

    É diferente pois o EF41 passa a validar o estado das entidades, veja esta imagem: http://ferhenriquef.files.wordpress.com/2011/10/060.png

    Aqui nesse caso dentro do método Salvar devemos passar a instância que deve ser atualizada para o método Entry e depois devemos mudar seu estado para Modified para que quando o método SaveChanges for chamado, ele ver que essa instância que foi modificada.

     

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    quarta-feira, 30 de novembro de 2011 18:53
    Moderador
  • Entendi.....obrigado pelo exemplo..

    Mas de qualquer forma antes de chamar o método salvar vou ter que  fazer um select pra posicionar na entidade. correto?

    quarta-feira, 30 de novembro de 2011 19:25
  • Não obrigatoriamente.

    Por exemplo,vamos imaginar que vc possui um cadastro de clientes em uma aplicação ASP.Net.

    E vc resolve abrir para edição um dos registros existentes no banco de dados, então vc consulta os registros e popula o seu formulário web com essas informações. Neste instante vc esta totalmente desconectado do banco de dados e seus dados estão na tela.

    Quando vc clicar no botão Salvar, para atualizar o registro com aqueles dados que estavam na tela, vc terá de montar uma instância de clientes com os dados do formulário. Até esse instante vc não esta conectado no banco de dados, pois os dados necessários para montar a tela vieram da tela.

    Logo depois de montada a instância de cliente, com os dados na tela, vc passa para a sua camada de persistência esse objeto com os dados populados e altera o status da entidade para Modified. Isso já é suficiente para o EF41 detectar que a entidade estava vinculada ao banco de dados e que tem campos a serem atualizados.

    Onde esta o segredo? O segredo esta no atributo de sua classe que corresponde a Primary Key, se este atributo for do tipo inteiro e for diferente de ZERO, então o EF41 irá procurar pela tupla correspondente em sua tabela.

    Faça alguns testes.

    No meu blog tenho publicado alguns experimentos com isso.

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.wordpress.com/
    Twitter: @ferhenrique
    • Sugerido como Resposta EvangelistaLion quinta-feira, 1 de dezembro de 2011 13:22
    quarta-feira, 30 de novembro de 2011 22:35
    Moderador
  • Excelente explicação...Entendi perfeitamente....Muito obrigado Fernando..

    Vou visitar seu blog...


    quinta-feira, 1 de dezembro de 2011 13:21