none
EntityFramework salvando relacionamento em duplicidade RRS feed

  • Pergunta

  • Olá pessoal,

    Estou tendo um problema na minha aplicação quando estou salvando um novo cliente. Ao efetuar esta ação todas as tabelas de relacionamentos envolvidos nesta View são acrescidos de uma nova linha nas tabelas relacionadas  (Sexo, Tipo Pessoa e etc...). Acontece que a única tabela que deveria receber um novo registro seria a de Clientes. Já tentei com o lazy loading true e false. 

    Obs.: O meu projeto esta em DDD.

    Grato pela força!

    segunda-feira, 28 de setembro de 2015 04:36

Respostas

  • Você deve falar para o Framework ORM Entity as suas configurações ou com decoradores ou com classes de mapeamento, e também tomar cuidado com nomes que fazem referencia a outras entidades de relacionamento tipo você colocou public virtual IEnumerable<Cliente> IdCliente {get;set;}, não pode fazer assim porque IdCliente da relação é um campo chave da sua outra Entidade.

    Eu fiz algumas configurações nas duas que você me passou para que tu teste ai, segue logo abaixo:

    [Table("EstadoCivil")]
    public class EstadoCivil
    {
    	public EstadoCivil()
    	{
    	}
    
    	[Key()]
    	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    	public int IdEstadoCivil { get; set; }
    	public string DescricaoEstadoCivil { get; set; }
    
    	[ForeignKey("IdEstadoCivil")]
    	public virtual ICollection<Cliente> Clientes { get; set; }
    
    }
    
    [Table("Cliente")]
    public class Cliente
    {
    	public Cliente()
    	{
    	}
    
    	[Key()]
    	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    	public int IdCliente { get; set; }
    
    	public string ClienteNome { get; set; }
    
    	public DateTime? ClienteDataNascimento { get; set; }
    
    	public string ClienteNumeroCpf { get; set; }
    
    	public string ClienteNumeroRg { get; set; }
    
    	public string ClienteProfissao { get; set; }
    
    	public string ClienteTelefoneResidencial { get; set; }
    
    	public string ClienteTelefoneCelular { get; set; }
    
    	public string ClienteTelefoneComercial { get; set; }
    
    	public string ClienteEmailPessoal { get; set; }
    
    	public DateTime DataCadastro { get; set; }
    			
    	public int IdFlagStatus { get; set; } 
    	public int IdEstadoCivil { get; set; } 
    	public int IdSexo { get; set; } 
    	public int IdUsuario { get; set; } 
    
    	[ForeignKey("IdFlagStatus")]
    	public virtual FlagStatus FkIdFlagStatus { get; set; }
    
    	[ForeignKey("IdEstadoCivil")]
    	public virtual EstadoCivil FkIdEstadoCivil { get; set; }
    
    	[ForeignKey("IdSexo")]
    	public virtual Sexo FkIdSexo { get; set; }
    
    	[ForeignKey("IdUsuario")]
    	public virtual Usuario FkIdUsuario { get; set; }
    
    }

     Isso é um tipo de mapeamento (tem muitos que não gosto assim e preferem o que é feito por classes) que é igual nesse link: http://ferhenriquef.com/2012/03/12/entitytypeconfiguration/ e https://msdn.microsoft.com/en-us/library/gg696117(v=vs.113).aspx


    Fulvio Cezar Canducci Dias

    • Marcado como Resposta urlflavio terça-feira, 29 de setembro de 2015 02:36
    segunda-feira, 28 de setembro de 2015 19:05

Todas as Respostas

  • Olá pessoal,

    Estou tendo um problema na minha aplicação quando estou salvando um novo cliente. Ao efetuar esta ação todas as tabelas de relacionamentos envolvidos nesta View são acrescidos de uma nova linha nas tabelas relacionadas  (Sexo, Tipo Pessoa e etc...). Acontece que a única tabela que deveria receber um novo registro seria a de Clientes. Já tentei com o lazy loading true e false. 

    Obs.: O meu projeto esta em DDD.

    Grato pela força!

    Poste os códigos referente a esse problema, porque não é realmente para acontecer isso!!!

    Fulvio Cezar Canducci Dias

    segunda-feira, 28 de setembro de 2015 13:56
  • Vou postar os blocos deste projeto.

    Relacionamento Pai Estado Civil 1:N (os demais seguem a mesma lógica):

    using System.Collections.Generic;

    namespace loja.Dominio.Entidades
    {
        public class EstadoCivil
        {
            public int IdEstadoCivil { get; set; }

            public string DescricaoEstadoCivil { get; set; }

            //Relacionamento Pai/Filho definindo 1:N
            public virtual IEnumerable<Cliente> IdCliente { get; set; }
        }
    }

    Relacionamento Filho (esta é a tabela principal e onde deve ser gravado os registros):

    using System;
    using System.Collections.Generic;

    namespace loja.Dominio.Entidades
    {
        public class Cliente
        {
            public Cliente(){}

            /*Dados Pessoais*/
            public int IdCliente { get; set; }
            
            public string ClienteNome { get; set; }

            public DateTime? ClienteDataNascimento { get; set; }

            public string ClienteNumeroCpf { get; set; }

            public string ClienteNumeroRg { get; set; }

            public string ClienteProfissao { get; set; }

            public string ClienteTelefoneResidencial { get; set; }

            public string ClienteTelefoneCelular { get; set; }

            public string ClienteTelefoneComercial { get; set; }

            public string ClienteEmailPessoal { get; set; }

            public DateTime DataCadastro { get; set; }

            //Relacionamento Pai/Filho
            public int IdFlagStatus { get; set; } //Ativo - Inativo - Suspenso
            public int IdEstadoCivil { get; set; } //Casado - Solteiro - Divorciado...
            public int IdSexo { get; set; } //Masculino - Feminino
            public int IdUsuario { get; set; } // Usuário responsável pelo cadastro

            public virtual FlagStatus FkIdFlagStatus { get; set; }

            public virtual EstadoCivil FkIdEstadoCivil { get; set; }

            public virtual Sexo FkIdSexo { get; set; }

            public virtual Usuario FkIdUsuario { get; set; }

        }
    }

    Dados recebidos do usuário através do método Post:

            [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult ClienteCadastrar(ViewModelCliente cliente)
            {
                if (ModelState.IsValid)
                {
                    try
                    {
                        var dominioCliente = Mapper.Map<ViewModelCliente, Cliente>(cliente);
                        _appCliente.Add(dominioCliente); //Rotina de Gravação dos Dados
                        return (ActionResult)RedirectToAction("Index");
                    }
                    catch (Exception)
                    {
                        ViewBag.FlagStatus = _appSelFlagStatus.GetAll().OrderBy(x => x.IdFlagStatus);
                        ViewBag.EstadoCivil = _appSelEstadoCivil.GetAll().OrderBy(x => x.IdEstadoCivil);
                        ViewBag.Sexo = _appSelSexo.GetAll().OrderBy(x => x.IdSexo);
                        //Incluir Notificação de Falha (View especifica)
                        return View(cliente);
                    }
                }
                ViewBag.FlagStatus = _appSelFlagStatus.GetAll().OrderBy(x => x.IdFlagStatus);
                ViewBag.EstadoCivil = _appSelEstadoCivil.GetAll().OrderBy(x => x.IdEstadoCivil);
                ViewBag.Sexo = _appSelSexo.GetAll().OrderBy(x => x.IdSexo);
                return View(cliente);
            }
           

    Gravando os dados:

    namespace loja.Repositorio.Repositorios
    {
        public class RepositorioBase<TEntity> : IDisposable,IRepositorioBase<TEntity> where TEntity : class
        {
            protected ArquiteturaContexto Db = new ArquiteturaContexto();

            public void Add(TEntity obj)
            {
                using (Db)
                {
                    Db.Set<TEntity>().Add(obj);
                    Db.SaveChanges();
                }
            }

    Após a gravação a tabela Estado Civil (bem como os demais relacionamentos) recebe mais uma linha sendo que somente a tabela Cliente deveria ser acrescida deste novo registros!

    segunda-feira, 28 de setembro de 2015 14:41
  • Você deve falar para o Framework ORM Entity as suas configurações ou com decoradores ou com classes de mapeamento, e também tomar cuidado com nomes que fazem referencia a outras entidades de relacionamento tipo você colocou public virtual IEnumerable<Cliente> IdCliente {get;set;}, não pode fazer assim porque IdCliente da relação é um campo chave da sua outra Entidade.

    Eu fiz algumas configurações nas duas que você me passou para que tu teste ai, segue logo abaixo:

    [Table("EstadoCivil")]
    public class EstadoCivil
    {
    	public EstadoCivil()
    	{
    	}
    
    	[Key()]
    	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    	public int IdEstadoCivil { get; set; }
    	public string DescricaoEstadoCivil { get; set; }
    
    	[ForeignKey("IdEstadoCivil")]
    	public virtual ICollection<Cliente> Clientes { get; set; }
    
    }
    
    [Table("Cliente")]
    public class Cliente
    {
    	public Cliente()
    	{
    	}
    
    	[Key()]
    	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    	public int IdCliente { get; set; }
    
    	public string ClienteNome { get; set; }
    
    	public DateTime? ClienteDataNascimento { get; set; }
    
    	public string ClienteNumeroCpf { get; set; }
    
    	public string ClienteNumeroRg { get; set; }
    
    	public string ClienteProfissao { get; set; }
    
    	public string ClienteTelefoneResidencial { get; set; }
    
    	public string ClienteTelefoneCelular { get; set; }
    
    	public string ClienteTelefoneComercial { get; set; }
    
    	public string ClienteEmailPessoal { get; set; }
    
    	public DateTime DataCadastro { get; set; }
    			
    	public int IdFlagStatus { get; set; } 
    	public int IdEstadoCivil { get; set; } 
    	public int IdSexo { get; set; } 
    	public int IdUsuario { get; set; } 
    
    	[ForeignKey("IdFlagStatus")]
    	public virtual FlagStatus FkIdFlagStatus { get; set; }
    
    	[ForeignKey("IdEstadoCivil")]
    	public virtual EstadoCivil FkIdEstadoCivil { get; set; }
    
    	[ForeignKey("IdSexo")]
    	public virtual Sexo FkIdSexo { get; set; }
    
    	[ForeignKey("IdUsuario")]
    	public virtual Usuario FkIdUsuario { get; set; }
    
    }

     Isso é um tipo de mapeamento (tem muitos que não gosto assim e preferem o que é feito por classes) que é igual nesse link: http://ferhenriquef.com/2012/03/12/entitytypeconfiguration/ e https://msdn.microsoft.com/en-us/library/gg696117(v=vs.113).aspx


    Fulvio Cezar Canducci Dias

    • Marcado como Resposta urlflavio terça-feira, 29 de setembro de 2015 02:36
    segunda-feira, 28 de setembro de 2015 19:05
  • Olá Fulvio,

    Acontece que já estou utilizando o Automapper + IoC+ Fluent API e mesmo assim este erro persiste. Já havia visto o site do Fernando entre outros. Estou mudando a forma como trato a gravação no repositório, ou seja, ao invés de receber os dados da view e enviá-los ao repositório genérico, vou criar uma rotina de gravação atachando as Fk´s antes de efetivar o SaveChanges dentro do repositório Clientes.

    Retorno dizendo se deu certo.

    segunda-feira, 28 de setembro de 2015 22:57
  • Só uma dica, olhe seus relacionamentos ... eu acredito que tenha conflito nisso.

    Fulvio Cezar Canducci Dias

    terça-feira, 29 de setembro de 2015 00:14
  • Fulvio,

    Aproveitei algumas das suas dicas do post anterior, mas de qualquer forma consegui gravar sem duplicidade utilizando o Atach (acho que é assim que diz :)).

    Mais uma vez Obrigado!!!

    terça-feira, 29 de setembro de 2015 02:36