Array
(
)

Problemas com Relacionamento Many to Many no Entity Framework 5.0.0

Kassio Silva
   - 18 out 2013

Olá Pessoal, tudo bem?
Estou desenvolvendo uma aplicação simples com C#, utilizando o Entity Framework v5.0.
Minha dúvida é a seguinte, criei duas classes, onde uma é EmpresaFornecedora e outra é Contato.
Fiz um mapeamento Muitos pra Muitos.
Só que no unit test com NUnit eu consigo inserir normalmente a empresa e o contato, porém quando vou removê-los no TearDown dá o Erro " System.InvalidOperationException : Não é permitido adicionar uma relação com uma entidade que está no estado Deleted."
Se eu comentar a linha em que estou relacionando o contato com a empresaFornecedora, funciona normal.
Como que faço para excluir junto com o contato e empresaFornecedora, o registro da tabela de relacionamento EmpresaFornecedora_Contato ?
Segue meus códigos:
#Código

public class Context : DbContext
    {
        public DbSet<EmpresaFornecedora> EmpresasFornecedoras { get; set; }

        public DbSet<Endereco> Enderecos { get; set; }

        public DbSet<Contato> Contatos { get; set; }

        public DbSet<UsuarioSistema> UsuarioSistemas { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

            modelBuilder.Entity<EmpresaCliente>().HasMany(c => c.Contatos).WithMany(e => e.EmpresasClientes)
                .Map(m =>
                {
                    m.MapLeftKey("EmpresaClienteId");
                    m.MapRightKey("ContatoId");
                    m.ToTable("Contato_EmpresaCliente");
                });

            modelBuilder.Entity<EmpresaFornecedora>().HasMany(c => c.Contatos).WithMany(e => e.EmpresasFornecedoras)
                .Map(m =>
                {
                    m.MapLeftKey("EmpresaFornecedoraId");
                    m.MapRightKey("ContatoId");
                    m.ToTable("Contato_EmpresaFornecedora");
                });

            modelBuilder.Entity<Funcionario>().HasMany(c => c.Contatos).WithMany(f => f.Funcionarios)
                .Map(m =>
                {
                    m.MapLeftKey("FuncionarioId");
                    m.MapRightKey("ContatoId");
                    m.ToTable("Contato_Funcionario");
                });

            modelBuilder.Entity<Tecnico>().HasMany(c => c.Contatos).WithMany(t => t.Tecnicos)
                .Map(m =>
                {
                    m.MapLeftKey("TecnicoId");
                    m.MapRightKey("ContatoId");
                    m.ToTable("Contato_Tecnico");
                });

            base.OnModelCreating(modelBuilder);
        }
    }


#Código
public abstract class EmpresaFornecedora : BaseEntidade
    {
        [Required(ErrorMessage = "O preenchimento do campo NOME é necessário.")]
        [MaxLength(100, ErrorMessage = "O tamanho máximo é de 100 caractéres.")]
        public string RazaoSocial { get; set; }

        [Required(ErrorMessage = "O preenchimento do campo NOME FANTASIA é necessário.")]
        [MaxLength(100, ErrorMessage = "O tamanho máximo é de 100 caractéres.")]
        public string NomeFantasia { get; set; }

        [Required(ErrorMessage = "O preenchimento do campo CNPJ é necessário.")]
        [MaxLength(20, ErrorMessage = "O tamanho máximo é de 20 caractéres.")]
        [PropriedadeComparavel]
        public string Cnpj { get; set; }

        [Required(ErrorMessage = "O preenchimento do campo IE é necessário.")]
        [MaxLength(20, ErrorMessage = "O tamanho máximo é de 20 caractéres.")]
        public string Ie { get; set; }

        public virtual Endereco Endereco { get; set; }

        public virtual ICollection<Contato> Contatos { get; set; }

        public virtual UsuarioSistema UsuarioSistema { get; set; }
    }

#Código
public class Contato : BaseEntidade
    {
        [Required(ErrorMessage = "O preenchimento do campo DESCRIÇÃO é necessário.")]
        [MaxLength(80, ErrorMessage = "O tamanho máximo é de 80 caractéres.")]
        public string Descricao { get; set; }

        [Required(ErrorMessage = "O preenchimento do campo TIPO é necessário.")]
        public virtual TipoContato TipoContato { get; set; }

        public virtual ICollection<EmpresaFornecedora> EmpresasFornecedoras { get; set; }

    }

#Código
 public abstract class BaseNegocio<T> where T : class
    {
        protected Context Context;

        protected BaseNegocio()
        {
            Context = Repositorio.Instanciar();
        }

        public virtual void Inserir(T objeto)
        {
            try
            {
                Context.Set<T>().Add(objeto);
                Context.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                string msgErro = string.Empty;
                var erros = Context.GetValidationErrors();

                msgErro = erros.SelectMany(erro => erro.ValidationErrors).Aggregate(msgErro, (current, detalheErro) => current + (detalheErro.ErrorMessage + "\n"));
                Context.Entry(objeto).State = EntityState.Detached;
                throw new InvalidOperationException(msgErro);
            }
        }

        public virtual void Alterar(T objeto)
        {
            try
            {
                Context.Entry(objeto).State = EntityState.Modified;
                Context.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                string msgErro = string.Empty;
                var erros = Context.GetValidationErrors();

                msgErro = erros.SelectMany(erro => erro.ValidationErrors).Aggregate(msgErro, (current, detalheErro) => current + (detalheErro.ErrorMessage + "\n"));
                Context.Entry(objeto).State = EntityState.Detached;
                throw new InvalidOperationException(msgErro);
            }
        }

        public virtual void Excluir(int id)
        {
            var objeto = Context.Set<T>().Find(id);

            if (objeto == null)
                throw new InvalidOperationException("Não existe um registro com a(s) característica(s) informada(s).");

            try
            {
                Context.Set<T>().Remove(objeto);
                Context.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                string msgErro = string.Empty;
                var erros = Context.GetValidationErrors();

                msgErro = erros.SelectMany(erro => erro.ValidationErrors).Aggregate(msgErro, (current, detalheErro) => current + (detalheErro.ErrorMessage + "\n"));
                Context.Entry(objeto).State = EntityState.Detached;
                throw new InvalidOperationException(msgErro);
            }
        }

        public virtual List<T> RetornarTodos()
        {
            var objetos = Context.Set<T>();

            return objetos.ToList();
        }

        public virtual T RetornarPorId(int id)
        {
            var objeto = Context.Set<T>().Find(id);

            if (objeto == null)
                return null;

            return objeto;
        }
    }


#Código
    public class EmpresaFornecedoraNegocio : BaseNegocio<EmpresaFornecedora>
    {
    }

#Código
[TestFixture]
    public class EmpresaFornecedoraNegocioTeste : IBaseTeste
    {
        private EmpresaFornecedoraNegocio empresaFornecedoraNegocio;
        private EnderecoNegocio enderecoNegocio;
        private ContatoNegocio contatoNegocio;
        private UsuarioSistemaNegocio usuarioSistemaNegocio;
        private EmpresaFornecedora empresaFornecedora1, empresaFornecedora2;

        [TestFixtureSetUp]
        public void InicializarClasseDeTestes()
        {
            //Instanciando repositório de empresas fornecedoras
            empresaFornecedoraNegocio = new EmpresaFornecedoraNegocio();

            //Instanciando repositório de endereços
            enderecoNegocio = new EnderecoNegocio();

            //Instanciando repositório de contatos
            contatoNegocio = new ContatoNegocio();

            //Instanciando repositório de usuários sistema
            usuarioSistemaNegocio = new UsuarioSistemaNegocio();

            //Ambiente para os demais métodos de testes

            var endereco1 = new Endereco()
            {
                Logradouro = "Rua 11",
                Numero = "0022",
                Bairro = "Centro",
                Cidade = "Guaíra",
                Cep = "14790000",
                Estado = "SP",
                Pais = "Brasil"
            };

            var endereco2 = new Endereco()
            {
                Logradouro = "Rua 45",
                Numero = "0062",
                Bairro = "Centro",
                Cidade = "Barretos",
                Cep = "15688009",
                Estado = "SP",
                Pais = "Brasil"
            };

            //enderecoNegocio.Inserir(endereco1);
            //enderecoNegocio.Inserir(endereco2);

            var contato1 = new Contato()
            {
                Descricao = "email@email.com.br",
                TipoContato = TipoContato.EMAIL
            };

            var contato2 = new Contato()
            {
                Descricao = "17993202344",
                TipoContato = TipoContato.CELULAR
            };
    
            //contatoNegocio.Inserir(contato1);
            //contatoNegocio.Inserir(contato2);

            var usuarioSistema1 = new UsuarioSistema()
            {
                Usuario = "jose.s",
                Senha = "123321",
                Nivel = 1
            };

            var usuarioSistema2 = new UsuarioSistema()
            {
                Usuario = "joao.a",
                Senha = "654321",
                Nivel = 1
            };

            //usuarioSistemaNegocio.Inserir(usuarioSistema1);
            //usuarioSistemaNegocio.Inserir(usuarioSistema2);

            empresaFornecedora1 = new EmpresaFornecedora
                {
                    RazaoSocial = "Intersoft Soluções LTDA",
                    NomeFantasia = "Intersoft Soluções",
                    Cnpj = "213123123123",
                    Ie = "123123123123",
                    Endereco = endereco1,
                    UsuarioSistema = usuarioSistema1,
                    Contatos = new Collection<Contato> {contato1}
                };

            empresaFornecedora2 = new EmpresaFornecedora
                {
                    RazaoSocial = "Softnet Soluções LTDA",
                    NomeFantasia = "Softnet Soluções",
                    Cnpj = "8282378387",
                    Ie = "12312313009",
                    Endereco = endereco2,
                    UsuarioSistema = usuarioSistema2,
                    Contatos = new Collection<Contato> {contato1},
                };
        }

        [TearDown]
        public void LimparCenarioDeTestes()
        {
            var retornoEmpresa = empresaFornecedoraNegocio.RetornarTodos();
            var retornoContato = contatoNegocio.RetornarTodos();
            var retornoEndereco = enderecoNegocio.RetornarTodos();
            var retornoUsuario = usuarioSistemaNegocio.RetornarTodos();


            //Exluindo EmpresasFornecedoras inseridos no decorrer dos testes
            if (retornoEmpresa.Any())
            {
                foreach (var empresa in retornoEmpresa)
                {
                    empresaFornecedoraNegocio.Excluir(empresa.Id);
                }
            }

            //Exluindo Usuários inseridos no decorrer dos testes
            if (retornoUsuario.Any())
            {
                foreach (var usuario in retornoUsuario)
                {
                    usuarioSistemaNegocio.Excluir(usuario.Id);
                }
            }

            //Exluindo Contatos inseridos no decorrer dos testes
            if (retornoContato.Any())
            {
                foreach (var contato in retornoContato)
                {
                    contatoNegocio.Excluir(contato.Id);
                }
            }

            //Exluindo Endereços inseridos no decorrer dos testes
            if (retornoEndereco.Any())
            {
                foreach (var endereco in retornoEndereco)
                {
                    enderecoNegocio.Excluir(endereco.Id);
                }
            }
        }

        [Test]
        public void PodeInserirTeste()
        {
            //Ação
            empresaFornecedoraNegocio.Inserir(empresaFornecedora1);

            //Assertivas
            var retorno = empresaFornecedoraNegocio.RetornarPorId(empresaFornecedora1.Id);

            Assert.IsNotNull(empresaFornecedora1);
            Assert.IsNotNull(retorno);
            Assert.AreEqual(retorno.Id, empresaFornecedora1.Id);
        }
    }