none
Metodologia de uso do datacontext RRS feed

  • Pergunta

  • Ola

    Estou usando uma metodologia para se trabalhar com o LINQ mais estou com alguns problemas...

    Bom, o metodo que estou usando é: criar uma insntacia do DATA CONTEXT para cada metodo que trabalha com os dados...

    exemplo, eu tenho na camada de DAO dois metodos:

    Uma para pesquisar e outra para inserir a noticia... cada um desses cria uma instancia do data context

    CODE
    Noticia GetNoticiaByID(int idnoticia) 
    {
    using (MeuDataContext db = new MeuDataContext())
      {
            var query = ...
            return (Noticia)query.single();
      }
    }


    bool UpdateNoticia(Noticia noticia)
    {
    using (MeuDataContext db = new MeuDataContext())
      {
         db.SubmitChanges();  
      }
    }


    MAIS, agora estou com o seguinte problema...

    Quando preciso ATUALIZAR ou DELETAR uma instancia de NOTICIA eu estou com problmeas...

    Imagine:

    - Eu crio uma instancia de NOTICIA por um metodo encapsulado na camada de DAO DAO.GetNoticiaByID(int idnoticia)
    - Ao retornar a noticia eu tento ATUALIZAR alguns campos

    noticia.assunto = "ASSUNTO EDITADO";

    - Agora eu irei ATUALIZAR a noticia usando o metodo DAO.UpdateNoticia(Noticia noticia)
    - PRONTO, aqui não atualiza pq em cada metodo que manipula os acessos a dados eu CRIO uma instancia do data context... BOM, eu imagino que seja este o problema rs

    Agora a duvida é .... COMO atualizarei uma instancia usando essa metodologia de criar uma DataContext para cada ação?

    Ou existe uma metodologia melhor que a minha?

    Obrigado
    quinta-feira, 18 de setembro de 2008 12:26

Todas as Respostas

  • E ai meu velho.

    Eu passei pelo mesmo problema,e resolvi da seguinte forma:
    Você terá que pegar o objeto noticia novamente utilizando o datacontext do metodo update e setar o que os valores neste objeto, em seguida é so da submitchanges();

    Ex: public bool Update(Noticia pNoticia)
    {
    using (MeuDataContext db = new MeuDataContext())
      {
            Noticia noticia=db.Noticias.Sigle(n=>n.ID_noticia==pNoticia.ID_Noticia);
    noticia.assunto=pNoticia.assunto;
         db.SubmitChanges(); 
            return true;
      }

    }

    Mas eu aconselho vc colocar um datacontext global.
    O grande problema que eu estou tendo é com relecionamentos n para m. por exemplo: O usuário tem uma lista de perfis, onde eu posso add um perfil selecionado em um list no usuario que esta sendo atualizado.
    Quando eu mando um submitchanges ele informa que não pode conter uma entidade que foi carregada por outro datacontext.
    Tenho soluções para isto mas são custosas e demanda maior trabalho.

    Você tem alguma idéia?

    Obrigado.





    segunda-feira, 13 de outubro de 2008 21:53
  • Como assim usar um DataContext global??

    Realmente, não vejo outra solução a não ser esta.

    Mais tb vi esse problema com as agregações... 

    to achando que a solução é buscar novamente CADA ELEMENTO da agregação e fazer a mesma coisa do objeto Noticia que é REATRIBUIR os valores

    using (MeuDataContext db = new MeuDataContext())
      {
          Noticia noticia=db.Noticias.Sigle(n=>n.ID_noticia==pNoticia.ID_Noticia);
    noticia.assunto=pNoticia.assunto;

    foreach (Perfil p in pNoticia.Perfis)
    perfilAdd = db.Perfis.Sigle(n=>n.ID_Perfil==p.ID_Perfil);
    noticia.perfis.Add(perfilAdd);
    }

    db.SubmitChanges(); 
          return true;
      }
    }


    Acho que assim seria uma solução, MAIS VEJO outro problema, é no caso de DELETAR UM FILHO de noticia??
    rs

    Vlwwww
    terça-feira, 14 de outubro de 2008 12:37
  • Você cria um dataContext global mesmo

    é o método mais simples e cria todos métodos que desejar dentro dele

     

    evita a necessidade de criar toda hora

    e apenas uma instancia, sempre executa na mesma instancia

     

    abraços

     

    quinta-feira, 6 de novembro de 2008 16:40
  • sim, eu estou fazendo isso em outra classe...

     

    eh q eu estou dividindo minha aplicação em 3 camadas..

     

    na camada de negocio eu uso uma classe chamada SessaoDAL() e é nesta classe que eu faço os selects e tal...

     

    nela eu uso um datacontext global...!!

     

    O problema esta na camada de apresentação... isso pq se eu carrego um relacionamento usando LoadWith eu tenho um errro na apresentação... se usar DefferendLoadEnable = false e usar acessar na apresentação uma propriedade, ele me da outro erro!

     

    To achando que a microsoft piso na bola pq não pensaram em projetos com camadas!

     

    Mas se alguem tiver uma ideia de como usar isso em 3 camadas ficaria muito grato...

     

    mais assim, de uma forma que atenda os seguintes requisitos:

     

    - Carregar um objeto, ou uma lista, ONDE eu não precise para cada propriedade de relacionamento (Produto.Cidade) fazer uma query no sql server QUANDO usa-la. Ou seja, carregar junto usando inner join (LoadWith<Cidade>()).

    - Poder acessar a propriedade Cidade.IdCidade sem nenhum problema, pois usando LoadWIth ele amarra essa propriedade e isso me causa um problema pois existe momentos que eu precise altera-la. Ou seja, que eu consigue usar as classe do datacontext como se fossem objetos de valor!! O NHibernate faz isso muito bem!

     

    Bem, seria isso!

     

    Obrigado

     

     

    quinta-feira, 6 de novembro de 2008 19:39
  •  

    Olha... eu costumo usar a propria classe do DataContext (criando um outro .cs e usando o Partial) e coloco uma propriedade estatica....

     

    [Arquivo MyDataContext.cs]

    partial class MyDataContext {

    internal static MyDataContext Current;

    }

     

    Como normalmente eu trabalho com linq dentro de WebService... eu intancio o MyDataContext.Currente na Inicialização do serviço e do o dispose na finalização dele (usando o metodo ~MyService), tipo:

     

    [Arquivo MyService.asmx]

     

    public MyService() {

         MyDataContext.Current = new MyDataContext();

    }

     

    ~MyService() {

    try { MyDataContext.Current.Dispose(); } catch { }

    }

     

     

    segunda-feira, 24 de novembro de 2008 19:58
    Moderador
  •  

    mais dessa forma, usando um static pra armazenar uma UNICA instancia do data context não pode ser perigoso...

     

    imagine uma situãção onde usuário A insere um registro, no momento seguinte o usuário B que não tem nada ha ver com a historia atualiza outro registro e da um Submit()...PRONTO, as alterações que seriam da TRANSAÇÃO do usuário A acabam de sere feitas msm sabendo que ela pertence ao usuário A...

     

    talvez em um ambiente windows forms esse problema seja menor, mais num sistem web as coisas complicam um pouco..

     

    vlw

    terça-feira, 25 de novembro de 2008 11:21
  •  

    Entao... foi como eu disse... uso iso somente dentro de um webservice..... ai eu controlo isso usando o

    [WebMethod(TransactionOption = TransactionOption.Required)]

     

    por exemplo:

     

    Code Snippet

    using System.EnterpriseServices;

     

    [WebMethod(TransactionOption = TransactionOption.Required)]

    public Cliente SetCliente(Cliente cliente) {

    try {

    // Verifica se existe o cliente na base

    var consulta = DataContext.Current.Cliente.SingleOrDefault(c => c.ID == cliente.ID);

     

    if (consulta == null) {

    // Inclusão

    DataContext.Current.Client.InsertOnSubmit(cliente);

    } else {

    // Alteraçao

    // Aqui uso um metodo para copiar todas as propriedades de um objeto para outro do mesmo tipo usando o System.Reflection...

     

    consulta.CopyFrom(cliente);

    }

     

    DataContext.Current.SumbitChanges();

    ContextUtil.SetComplete();

     

    return cliente;

    } catch (Exception ex) {

    ContextUtil.SetAbort();

    throw ex;

    }

    }

     

     

    o ".CopyFrom" é isso aqui:

     

    Code Snippet

    using System;

    using System.Reflection;

     

    namespace Prodesp.Detran.Siga.Extensions {

    /// <summary>

    /// Metodos de extensÆo de objetos

    /// </summary>

    public static class ObjectExtensions {

    /// <summary>

    /// Copia os valores das propriedades para outro objeto de mesmo tipo

    /// </summary>

    /// <param name="origem">Objeto de origem</param>

    /// <param name="destino">Objeto de destino</param>

    public static void CopyFrom(this object origem, object destino) {

    // Verifica se os objetos sÆo do mesmo tipo

    if (origem.GetType() != destino.GetType())

    throw new InvalidCastException();

     

    // Carrega a lista de propriedades do objeto

    PropertyInfo[] propiedades = origem.GetType().GetProperties();

    foreach (var propriedade in propiedades) {

    // Verifica se a propriedade ‚ publica e se possui permissÆo de escrita

    if (propriedade.CanWrite && propriedade.PropertyType.IsPublic) {

    // Copia o valor do objeto de origem para o objeto de destino

    var valor = propriedade.GetValue(origem, null);

    propriedade.SetValue(destino, valor, null);

    }

    }

    }

    }

    }

     

     

    Assim cada metodo roda em uma transação exclusiva e resolve esse problema...

     

    Caso não va usar webservice, ainda tem o controle de transação do proprio linq... eu ainda não o usei, mas a metodologia seria similar... so tomando alguns cuidados com metodos recursivos que poderiam deixar o sistema lento....

     

     

    terça-feira, 25 de novembro de 2008 11:44
    Moderador
  • No caso de uma solução ASP.NET poderia ser usado o data context em uma variavel de Sessão... acho que ele não deve ocupar mais memoria que uma conexão ADO normal... e ja vi muitos sites q mantinham a conexão ADO na epoca do ASP que mantinham as coneções em Sessão...

     

    Dependeria da quantidade de acessos simultaneos.

     

    uma solução seria implementar uma classe WebForm com um DataContext no ViewStation talvez, assim vc manteria uma instancia para cada pagina individualmente... gera um pouco mais de trafico de dados na rede...

     

    Mas para ser sincero... particulamente não vejo muita vantagem em Linq2Sql em uma pagina asp... por esse e outros fatores... o ADO.NET e a metodoliga de DataSets acho que funciona de uma forma mais armonica com ASP.

    terça-feira, 25 de novembro de 2008 17:05
    Moderador
  • Então, acredito que usar essa metodogia é uma boa solução...mais ainda me preocupo com o SubmitChanges, penso que o cuidado deva ser muito grande devido o mesmo estar cheios de instancias pegas, alteradas...

     

    ou seja, quando executo submitchanges o problema pode ocorrer...

     

    mais acredito que qualquer ideia é valida e vou estudar esta tb...

     

    a minha ideia foi trabalhar desconectado, onde cada AÇÂO feita pela classe de negocio eu crio uma nova instancia do datacontext e quando esta ação termina eu destruo

     

    exemplo:

     

    public static InserirCliente(Cliente intancia)

    {

    using (DataContext a = new DataContext)

    {

    // insiro

    }

    }

     

    e para alterar:

     

    public static Alterar(Cliente intancia)

    {

    using (DataContext a = new DataContext)

    {

    // Localizo a intancia

    // Alterar do de acordo com a nova

    // Submit()

    }

    }

     

     

    e eu gostei muito da ideia de usar o reflection para abstrar os valores da nova propriedade para a antiga..

    eu atribuo de propriedade a propriedade e isso enche o saco pra c sincero... mais esse medoto esta abilidado pra trabalhar com propriedades filhos, agregações??

     

    bom, no geral vlw pelos posts ...

     

    obrigado a tds

    quarta-feira, 26 de novembro de 2008 16:11
  •  

    ah... é que eu tive alguns problemas fazendo isso...  se o paramentro tiver vindo de um outro DataContext por exemplo... da erro de que o objeto foi instancia em um data context diferente ou algo assim...

     

    se vc fizer um metodo recursivo dessa forma então nem pensar...

     

    Vou ficar atento aqui ao problema do SubmitChanges... mas relamente... cada instancia de WebService q eu carrego e SessionLess... acho que não tem como 2 usuarios acessarem o mesmo datacontext ja q seria uma instancia do meu service para cada usuario.... mas vou verificar...

     

    Sobre o reflection, sim.. eu trablho com herança aqui sim.... as propriedades filhos, sendo publicas, carregam sem probemas... agora agregações... confesso que não reparei... mas acho que devo ter alguma classe que tenha uma agregação entao acredti que funciona tambem...

     

     

     

    quarta-feira, 26 de novembro de 2008 17:18
    Moderador
  • realmente... no seu caso o risco do submitchanges eh muito pequeno...

     

    eu penso q eh uma boa solução para este problema...

     

    ja no caso de um site isso fica inviavel devido ao numero d pessoas usando o mesmo datacontext...

    com ctrz causaria resultados inesperados com usuarios fazendo submit de outros usuarios e entre outras...

     

    essa ideia de usar reflection eu tb tinha..mais estava sem tempo pra pesquisar, vou usar seu código como referencia e criar um para mim, tranquilo??

     

    mais enfim, vlw pelos posts...

     

    abraços

     

    quarta-feira, 26 de novembro de 2008 17:40
  •  

    Ola... então... o static não funciona heheheh ^^ forcei a situação aqui e ocorreu o seguinte erro:

     

    ---------------------------
    Erro
    ---------------------------
     A conexão atualmente tem transação inscrita. Conclua a transação atual e tente novamente.
    ---------------------------
    OK  
    ---------------------------

     

    Bem... ao menos não intercalou as operações.... vo tentar uma outra abordagem aqui....

     

    No mais.. pode usar sem problemas... ele é baseado em um outro codigo que achei na net mesmo....

     

    T+

    quarta-feira, 26 de novembro de 2008 19:51
    Moderador
  • So para constar voltei a fazer como fazia antigamente Tongue Tied....

     

    Detalhe que eu implemento todos as "operacoes Linq" nas classes das entidades... no fim ficou algo mais ou menos assim:

     

    Code Snippet

    public class Service: WebService {

          internal DataContext context;

          public Service() {

               this.context = new DataContext();

          }

         ~Service() {

              this.context.Dispose();

         }

     

        [WebMethod(TransactionOption = TransactionOption.Required)]

        public Cliente SalvarCliente(Cliente cliente) {

              cliente.Salvar(this.context);

    return cliente;

        }

    }

     

    partial class Cliente {

         public void Salvar(DataContext context) {

                //TODO: Efetuar Validações

                         

    var consulta = context.Cliente.SingleOrDefault(c => c.ID == this.ID);

    if (consulta == null) {

    context.Client.InsertOnSubmit(this);

    } else {

    consulta.CopyFrom(this);

    }

     

    context.SubmitChanges();

         }

    }

     

     

     

    Tenho q passar o DataContext como paramentro em todos os metodos... eu achava isso muito chato... mas é o jeito mesmo... pelo menos assim sei que funciona
    quarta-feira, 26 de novembro de 2008 20:23
    Moderador
  • entao... o static soh funciona se vc CRIAR uma nova instancia do datacontext...

     

    algo assim,

     

    using (DataContext db = new DataContext())

    {

    código

    }

     

    Soh que o DataContext deve estar configurado certinho com a string de conecção e td mais..

     

    naum vejo problemas sendo que é o msm código do que vc faz no construtor do webservice...

    sera q passo alguma coisa??

     

    mais enfin, a sua nova abordagem esta legal... o unico porem seria ter que passar o DataContext por parametro !!

     

    ehh..esse DataContext eh bom mais deixa muitas duvidas... e ainda não achei um bom modelo para se trabalhar na web com 3 camadas...

     

    Abs

     

    quinta-feira, 27 de novembro de 2008 12:04
  • é que acho q o Linq2Sql não foi feito para trabalhar em 3 camadas mesmo Tongue Tied.... o que eu ja tive de problemas com o .Attach() não é brincadeira...

     

    Mas um coisa q eu sempre configuro no DataContext quando vo trabalhar desconectado é o Serialization Mode como Unidirecional...

     

    Não lembro qual era o problema q eu tinha... mas lembro q fazendo isso resolvia...

    quinta-feira, 27 de novembro de 2008 12:16
    Moderador
  •  

    Olá Pessoal !

     

    Encontrei este link sobre o assunto:

     

    http://www.macoratti.net/08/02/lnq_ord1.htm

     

     

    Abraços,

     

     

    terça-feira, 27 de janeiro de 2009 18:07