none
Como adicionar um novo item a uma coleção (entidade relacionada/filha) quando o Pai já está salvo RRS feed

  • Pergunta

  • Boa tarde.

    Preciso de ajuda para a seguinte dúvida:

    Eu tenho uma entidade chamada Produto, ele possui uma entidade relacionada (coleção) chamado Fornecedor.

    Então o Objeto produtos terá vários filhos chamado Fornecedor.

    Quando eu faço um Add no Entity, com um novo Produto e um novo Fornecedor, o Entity salva corretamente, ele gera um registro na tabela de Produtos e um relacionado na tabela de Fornecedor. 

    Contudo, se eu salvar um Produto sem fornecedor, e depois tentar adicionar (criar um fornecedor) pra ele, o Entity não salva.

    Na Classe Produto eu tenho então:

            [DataMember]
            public ICollection<Fornecedor> Fornecedor { get; set; }

    A Classe Fornecedor:

            

     [DataContract(IsReference = true)]
        [Table("tblProdutosFornecedores")]
        public class Fornecedor 
        {

            [DataMember]
            [Key]
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public int FornecedorId { get; set; }

            [DataMember]
            public int ProdutoId { get; set; }

            [DataMember]
            public int PessoaId { get; set;  }

            [DataMember]
            [ForeignKey("PessoaId")]
            public virtual Pessoa Pessoa { get; set; }


        }

    O metodo que faz o "insert"

                  

      using (Contexto ctx = new Contexto())
                {
                    ctx.Produtos.Add(produto);
                    ctx.SaveChanges();

                    return true;
                }

    o metodo que faz o "update"

                    

     using (Contexto ctx = new Contexto())
                {
                    ctx.Entry(produto).State = EntityState.Added;

                    ctx.SaveChanges();
                    return true;

                }

    Observação: 

    No primeiro caso eu usei o método que faz o "insert" e no segundo (que não funciona) eu usei o método que faz o update. Se eu usar o método que faz o "insert" ele irá duplicar o produto.

    Para adicionar o fornecedor, eu usei o método Add na entidade relacionada Fornecedor, no objeto já populado com o registro que eu desejo adicionar o Fornecedor.

    Não sei como sinalizar para o Entity que eu quero adicionar um novo fornecedor ao produto já adicionado.

    Estou usando abordagem CodeFirst.

    Ricardo.

    terça-feira, 17 de janeiro de 2017 17:43

Respostas

  • Ricardo,

    De qualquer forma, discordo da sua modelagem, acredito que ela "engessa" seu modelo para novas possibilidades, mas ok, isso fica a seu critério.

    Primeiramente, o modo correto de indicar o update é com o EntityState.Modified mesmo.

    Acredito que esse problema esteja ocorrendo, pois antes você deve adicionar os novos fornecedores na Entidade de Fornecedor e adicioná-los ao contexto e só depois adicionar esses mesmos objetos na lista do produto. Acredito que dessa forma irá funcionar.

    Valeu!


    Se a resposta for relevante ou tenha resolvido seu problema, marque como útil/resposta!

    André Secco
    Microsoft MVP & MSDN Tech Advisor
    Blog: http://andresecco.com.br
    GitHub: http://github.com/andreluizsecco
    Twitter: @andre_secco

    • Marcado como Resposta Ricardo S Pulini quarta-feira, 18 de janeiro de 2017 10:44
    quarta-feira, 18 de janeiro de 2017 10:33

Todas as Respostas

  • Olá,

    Inicialmente, olhando rapidamente, acredito que sua modelagem esteja errada, uma vez que dessa forma o Fornecedor poderá ser vinculado apenas a 1 produto. O mais aconselhável seria ter o produto vinculado a um fornecedor. Mas claro, não como é seu seu cenário, porém dessa forma parece meio estranho.

    Dá uma olhada antes nessa modelagem, para aí sim prosseguir.


    Se a resposta for relevante ou tenha resolvido seu problema, marque como útil/resposta!

    André Secco
    Microsoft MVP & MSDN Tech Advisor
    Blog: http://andresecco.com.br
    GitHub: http://github.com/andreluizsecco
    Twitter: @andre_secco

    terça-feira, 17 de janeiro de 2017 18:20
  • Oi André, boa tarde. Obrigado pela sua interação.

    Eu acredito que não eu expliquei direito, vou tentar esclarecer: Meu objetivo na realidade é que um Produto X, possa estar relacionado a vários fornecedores, ou seja, eu quero poder adicionar (relacionar) vários fornecedores ao mesmo produto (1 pra muitos). Essa parte do processo esta ok, como eu relatei acima. Na UI, quando eu instancio um objeto Produto, e adiciono vários objetos filhos "Fornecedor" e envio para a BLL salvar conforme o metodo acima, o resultado é satisfatório. O problema é se eu já salvei o produto (sem nenhum fornecedor) e depois quero "alterar-lo" adicionando fornecedores a ele. Em uma primeira tentativa eu populei um objeto do tipo Produto, (utilizando o include na expressão linq para carregar o relacionamento com a tabela Fornecedores) , o Entity me retornou corretamente os dados, contudo a "coleção" Fornecedor estava vazia (correto pois eu não tinha adicionado nenhum fornecedor ainda), eu então utilizando o metodo Add "produto.Fornecedor.Add (fornecedor)" inclui nele 2 fornecedores. Até ai tudo bem, o problema vem agora, quando eu envio o objeto populado para a BLL fazer a persistência, eu tenho duas opções (até onde eu sei), ou eu marco a entidade "produto" para o Status "EntityState.Modified" ou para o Status "EntityState.Added", a primeira opção não faz nada, a segunda faz, mas cria um novo produto com os 2 fornecedores. 

            using (Contexto ctx = new Contexto())
                {
                    ctx.Entry(produto).State = EntityState.Modified;
                    ctx.SaveChanges();
                    return true;
                }

    Observando o objeto, neste ponto da execução, a coleção Fornecedor está agora com 2 itens, mas ele não "cria" os registros na tabela, ele só persiste alterações do objeto Produto, ignorando a necessidade da inclusão dos fornecedores.

    Eu resolvi este problema de uma forma mais simples, incluindo o fornecedor na tabela de relacionamento com um método auxiliar (através de um insert). Mas o eu queria saber na verdade e se via Entity, não existe uma maneira de sinalizar que o objeto/Entidade filho "Fornecedor" esta em modo Add e o pai não.

    Obrigado.

    quarta-feira, 18 de janeiro de 2017 10:01
  • Ricardo,

    De qualquer forma, discordo da sua modelagem, acredito que ela "engessa" seu modelo para novas possibilidades, mas ok, isso fica a seu critério.

    Primeiramente, o modo correto de indicar o update é com o EntityState.Modified mesmo.

    Acredito que esse problema esteja ocorrendo, pois antes você deve adicionar os novos fornecedores na Entidade de Fornecedor e adicioná-los ao contexto e só depois adicionar esses mesmos objetos na lista do produto. Acredito que dessa forma irá funcionar.

    Valeu!


    Se a resposta for relevante ou tenha resolvido seu problema, marque como útil/resposta!

    André Secco
    Microsoft MVP & MSDN Tech Advisor
    Blog: http://andresecco.com.br
    GitHub: http://github.com/andreluizsecco
    Twitter: @andre_secco

    • Marcado como Resposta Ricardo S Pulini quarta-feira, 18 de janeiro de 2017 10:44
    quarta-feira, 18 de janeiro de 2017 10:33
  • André, bom dia.

    Obrigado pela explicação e eu vou rever a modelagem conforme sua dica.

    Eu encontrei uma forma de resolver o problema, alterei o método dessa maneira:

                   

     using (Contexto ctx = new Contexto())
                {
                    ctx.Entry(produto).State = EntityState.Modified;
                    foreach (Fornecedor fornec in produto.Fornecedor)
                    {
                        if (fornec.FornecedorId == 0)
                        {
                            ctx.Entry(fornec).State = EntityState.Added;
                        }
                        else
                        {
                            ctx.Entry(fornec).State = EntityState.Modified;
                        }
                    }

                    ctx.SaveChanges();
                    return true;

                }

    Assim ele criou o registros.

    Obrigado novamente pelo apoio.

    Ricardo

    quarta-feira, 18 de janeiro de 2017 10:43