none
EF com CODE FIRST duas classes para a mesma TABELA RRS feed

  • Pergunta

  • Pessoal,

    estou tentando utilizar 2 classes diferentes para a mesma tabela e está dando erro.

    O sistema diz que não única a referência. Estou usando isto para fazer o login no sistema, tendo campos obrigatórios para o login, e estou usando outra classe para LoginCadastro para a mesma tabela com outros campos obrigatórios e o sistema se perde.

    Como posso resolver isto? Fontes abaixo.

    Classe usuário:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.ComponentModel.DataAnnotations;
    using System.Data.Entity.ModelConfiguration.Conventions;
    using System.Web.Mvc;
    
    namespace ERP.Models
    {
    
        public class Logar
        {
            [Required(ErrorMessage = "Login obrigatório")]
            [Display(Name = "Login no sistema")]
            public string Login { get; set; }
    
            [Required(ErrorMessage = "Informe a senha")]
            [DataType(DataType.Password)]
            [Display(Name = "Digite a senha")]
            public string Senha { get; set; }
        }
    
        public class UsuarioCadastro
        {
            [Required]
            [Display(Name = "Usuário")]
            public string Usuario { get; set; }
    
            [Required]
            [DataType(DataType.EmailAddress)]
            [Display(Name = "E-mail")]
            public string Email { get; set; }
    
            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }
    
            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }
    
    
    
    }

    CodeFirstContext:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Data.Entity;
    
    
    namespace ERP.Models
    {
        public class ERPCodeFirstContext : DbContext
        {
            public DbSet<CNAES> CNAES { get; set; }
            public DbSet<Logar> Usuario { get; set; }
            public DbSet<UsuarioCadastro> Usuario { get; set; }
    
    
            public ERPCodeFirstContext()
            {
                Database.SetInitializer<ERPCodeFirstContext>(null);            
            }       
    		
    		protected override void OnModelCreating(DbModelBuilder modelBuilder)
    		{
    			modelBuilder.Entity<CNAES>().ToTable("CNAES", schemaName: "ERP");
                modelBuilder.Entity<Logar>().ToTable("Usuario", schemaName: "ERP");
                modelBuilder.Entity<UsuarioCadastro>().ToTable("Usuario", schemaName: "ERP");            
    		}
    	}
    }

    Controler está abaixo e o erro acontece nesta linha:

    return View(db.UsuarioCadastro.ToList());



    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.UI.WebControls;
    using ERP.Models;
    using System.Web.Security;
    
    namespace ERP.Controllers
    {
        public class UsuarioController : Controller
        {
            //
            // GET: /Login/
    
            private ERPCodeFirstContext db = new ERPCodeFirstContext();
    
            public ActionResult LogOn()
            {
                return View(db.UsuarioCadastro.ToList());
            }
    
            [HttpPost]
            public ActionResult LogOn(Logar model)
            {
                if (ModelState.IsValid)
                {
                    if (Membership.ValidateUser(model.Login, model.Senha))
                    {
                        FormsAuthentication.SetAuthCookie(model.Login, true);
                        Session["configuracoes"] = new Configuracoes { UsuarioID = 10, Nome = model.Login };
                        return RedirectToAction("Index", "Home");
                    }
                }
                return View(model);
            }
    
            public ActionResult LogOff()
            {
                FormsAuthentication.SignOut();
                return RedirectToAction("Index", "Home");
            }
    
    
        }
    }

    Abs...


    Marlon Tiedt
    www.sesmt.com.br


    • Editado Marlon Tiedt segunda-feira, 4 de junho de 2012 14:43
    segunda-feira, 4 de junho de 2012 14:42

Respostas

  • Tenta criar outra classe e por a classe Logar e CadastroUsuario dentro e ai mapeia só esta.

    public class Login

    { public Logar Logar{get;set;}

    public CadastroUsuario{get;set;} }

    e:

    modelBuilder.Entity<Login>().ToTable("Usuario", schemaName: "ERP");

    Acho que vai funcionar.


    http://www.linkedin.com/pub/murilo-kunze/44/191/455


    • Editado Murilo Kunze segunda-feira, 4 de junho de 2012 15:28
    • Marcado como Resposta Marlon Tiedt terça-feira, 5 de junho de 2012 16:16
    segunda-feira, 4 de junho de 2012 15:27
  • Olá Marlon,
    Bem vindo novamente ao Fórum do MSDN :)

    No caso, vc não precisa necessariamente criar/mapear uma classe que contém os dados digitados pelo usuário para o banco de dados. Apenas a entidade que vc usou para registrar novos usuários já é suficiente.

    Qual a arquitetura da sua aplicação? Vc esta utilizando WCF ou WebServices? É uma aplicação ASP.Net?

    Se vc estiver utilizando uma arquitetura em camadas estilo MVC (Model View Controller) vc pode fazer algo como:

    Na camada de visão:

    public void ButtonX_Click(object sender, EverntArgs e)
    {
      AutenticacaoController aut = new AutenticacaoController();
      if (aut.Autenticar(this.txtUsuario.Text, this.txtSenha.Text)
      {
         Response.Redirect("OutraPagina.aspx");
      }
      else
      {
         this.lblMessage.Text = "Usuário ou senha incorretos.";
      }
    }

    Na Controller:

    public class AutenticacaoController 
    {
       public bool Autenticar(string usuario, string senha)
       {
          bool returnValue = false;
          AutenticacaoDados repositorio = new AutenticacaoDados();
          Usuario usuarioAtual = repositorio.GetUsuario(usuario);
          if (usuarioAtual != null)
          {
                if (usuarioAtual.Senha == senha)
                   returnValue = true;
          }
          return returnValue;
       }
    }

    Repare que neste caso apenas capturamos os dados digitados pelo usuário, e passamos para nossa classe Controller, que é a responsável por validar a autenticação do usuário. Veja que na classe Controller temos fazemos referência para a classe de acesso a dados, que retorna um usuário com base no nome de usuário digitado pelo usuário. Veja que não foi preciso mapear os dados digitados pelo usuário na hora do login com o banco de dados, apenas foi preciso comparar com os dados que estão na base de dados.

    Vc comentou que não conseguiu criar a procedure, tem alguma mensagem de erro? podemos ajudar de alguma forma?

    Com relação ao seu código, fiz algumas modificações, acredito que vá funcionar. Precisa apenas modificar os nomes das colunas para as colunas que realmente existe na sua base de dados.

            public override bool ValidateUser(string username, string password)
            {
                bool returnValue = false;
    
                var factory = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings["ERPCodeFirstContext"].ProviderName);
    
                var connection = factory.CreateConnection();
                connection.ConnectionString = ConfigurationManager.ConnectionStrings["ERPCodeFirstContext"].ConnectionString;
    
                connection.Open();
    
                var cmd = connection.CreateCommand();
                cmd.CommandText = "select TOP 1 Senha from Usuario where NomeUsuario = '" + username + "'";
    
    
                object result = cmd.ExecuteScalar()
                if (result != null) 
                {
                     if (result.ToString() == password)
                         returnValue = true;
                }	
    
                return returnValue;
            }

    Exemplos com a Fluent API:
    http://ferhenriquef.com/2011/11/26/construindo-sua-camada-de-acesso-a-dados-com-o-entity-framework-4-1/
    http://ferhenriquef.com/2012/03/12/entitytypeconfiguration/
    http://msdn.microsoft.com/en-us/library/hh295844(v=VS.103).aspx

    Uffa! Acredito que seja isso :)

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique

    • Marcado como Resposta Marlon Tiedt terça-feira, 5 de junho de 2012 16:16
    segunda-feira, 4 de junho de 2012 23:35
    Moderador

Todas as Respostas

  • Tenta criar outra classe e por a classe Logar e CadastroUsuario dentro e ai mapeia só esta.

    public class Login

    { public Logar Logar{get;set;}

    public CadastroUsuario{get;set;} }

    e:

    modelBuilder.Entity<Login>().ToTable("Usuario", schemaName: "ERP");

    Acho que vai funcionar.


    http://www.linkedin.com/pub/murilo-kunze/44/191/455


    • Editado Murilo Kunze segunda-feira, 4 de junho de 2012 15:28
    • Marcado como Resposta Marlon Tiedt terça-feira, 5 de junho de 2012 16:16
    segunda-feira, 4 de junho de 2012 15:27
  • Se eu te falar que pensei em fazer isto e não fiz...
    Vou testar com o banco de dados e te digo se funcionou.

    Abs

    Marlon Tiedt
    www.sesmt.com.br

    segunda-feira, 4 de junho de 2012 16:46
  • Olá Marlon,
    Tudo beleza?

    Apontar duas entidades para a mesma tabela é simples. Mas, não sei se será aplicável ao seu cenário, pois vc tem a repetição de propriedades entre as classes... por exemplo: em uma classe vc tem a propriedade Login e na outra Usuario, em uma vc tem Senha e na outra Password.

    Para fazer o Tablet Splitting (assim que se chama a técnica) vc deve ter algo como:

    public class Person
    {
    public int Id {get;set;}
    public string Name {get;set;}
    public DateTime BurnDay {get;set;} 
    }
    
    public class PersonPhoto
    {
    [Key, ForeignKey("PhotoOf")]
    public int PersonId {get;set;}
    public byte[] Photo {get;set;}
    
    // Repare que o atributo abaixo é mto importante...
    public Person PhotoOf {get;set;} }

    E depois configurar usando a Fluent API desta forma:

    modelBuilder.Entity<Person>().ToTable("Person");
    modelBuilder.Entity<PersonPhoto>().ToTable("Person");

    Outros detalhes para que esse mapeamento ocorra:
    - As entidades tem q ter um relacionamento um-para-um
    - As entidades devem compartilhar uma chave entre si

    Comente o que deseja fazer, talvez consigamos ajudá-lo com outra solução...

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique

    segunda-feira, 4 de junho de 2012 22:19
    Moderador
  • Olá Fernando, eu aqui de novo fazendo perguntas... :)...

    O que eu estou tentando fazer é usar um MembershipProvider para logar no sistema e fazer o cadastro de novos usuários.
    Então para logar os campos Login e Senha são obrigatórios.

    Já para cadastrar temos outros campos a mais para validar, exemplo Nome.

    Por isto pensei em modelar duas classes para a mesma TABELA. Outra coisa que ferrou isto, foi que não consegui  fazer a procedure ValidadeUser receber um model e comparar isto com valores no banco de dados. Então fiz da forma abaixo, abrindo uma nova conexão somente para isto, o resto fica conforme já estou usando.

            public override bool ValidateUser(string username, string password)
            {
    
                var factory = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings["ERPCodeFirstContext"].ProviderName);
    
                var connection = factory.CreateConnection();
                connection.ConnectionString = ConfigurationManager.ConnectionStrings["ERPCodeFirstContext"].ConnectionString;
    
                connection.Open();
    
                var cmd = connection.CreateCommand();
                cmd.CommandText = "select * from Usuario";
    
    
                if ((cmd.ExecuteReader().GetString(cmd.ExecuteReader().GetOrdinal("USUARIO"))) == password)
                {
                    return true;
                }
                else
                {
                    return false;
                }
    
    
            }


    Não sei se estou fazendo correto.

    Outra coisinha, vc teria algum exemplo de Fluent Api.

    Abs


    Marlon Tiedt
    www.sesmt.com.br

    segunda-feira, 4 de junho de 2012 23:08
  • Olá Marlon,
    Bem vindo novamente ao Fórum do MSDN :)

    No caso, vc não precisa necessariamente criar/mapear uma classe que contém os dados digitados pelo usuário para o banco de dados. Apenas a entidade que vc usou para registrar novos usuários já é suficiente.

    Qual a arquitetura da sua aplicação? Vc esta utilizando WCF ou WebServices? É uma aplicação ASP.Net?

    Se vc estiver utilizando uma arquitetura em camadas estilo MVC (Model View Controller) vc pode fazer algo como:

    Na camada de visão:

    public void ButtonX_Click(object sender, EverntArgs e)
    {
      AutenticacaoController aut = new AutenticacaoController();
      if (aut.Autenticar(this.txtUsuario.Text, this.txtSenha.Text)
      {
         Response.Redirect("OutraPagina.aspx");
      }
      else
      {
         this.lblMessage.Text = "Usuário ou senha incorretos.";
      }
    }

    Na Controller:

    public class AutenticacaoController 
    {
       public bool Autenticar(string usuario, string senha)
       {
          bool returnValue = false;
          AutenticacaoDados repositorio = new AutenticacaoDados();
          Usuario usuarioAtual = repositorio.GetUsuario(usuario);
          if (usuarioAtual != null)
          {
                if (usuarioAtual.Senha == senha)
                   returnValue = true;
          }
          return returnValue;
       }
    }

    Repare que neste caso apenas capturamos os dados digitados pelo usuário, e passamos para nossa classe Controller, que é a responsável por validar a autenticação do usuário. Veja que na classe Controller temos fazemos referência para a classe de acesso a dados, que retorna um usuário com base no nome de usuário digitado pelo usuário. Veja que não foi preciso mapear os dados digitados pelo usuário na hora do login com o banco de dados, apenas foi preciso comparar com os dados que estão na base de dados.

    Vc comentou que não conseguiu criar a procedure, tem alguma mensagem de erro? podemos ajudar de alguma forma?

    Com relação ao seu código, fiz algumas modificações, acredito que vá funcionar. Precisa apenas modificar os nomes das colunas para as colunas que realmente existe na sua base de dados.

            public override bool ValidateUser(string username, string password)
            {
                bool returnValue = false;
    
                var factory = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings["ERPCodeFirstContext"].ProviderName);
    
                var connection = factory.CreateConnection();
                connection.ConnectionString = ConfigurationManager.ConnectionStrings["ERPCodeFirstContext"].ConnectionString;
    
                connection.Open();
    
                var cmd = connection.CreateCommand();
                cmd.CommandText = "select TOP 1 Senha from Usuario where NomeUsuario = '" + username + "'";
    
    
                object result = cmd.ExecuteScalar()
                if (result != null) 
                {
                     if (result.ToString() == password)
                         returnValue = true;
                }	
    
                return returnValue;
            }

    Exemplos com a Fluent API:
    http://ferhenriquef.com/2011/11/26/construindo-sua-camada-de-acesso-a-dados-com-o-entity-framework-4-1/
    http://ferhenriquef.com/2012/03/12/entitytypeconfiguration/
    http://msdn.microsoft.com/en-us/library/hh295844(v=VS.103).aspx

    Uffa! Acredito que seja isso :)

    []s!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique

    • Marcado como Resposta Marlon Tiedt terça-feira, 5 de junho de 2012 16:16
    segunda-feira, 4 de junho de 2012 23:35
    Moderador
  • Olá Fernando, primeiro quero agradecer você e o Murilo Kunze por me ajudarem bastante aqui. Como sou programador Delphi, estou aprendendo os novos conceitos de MVC, C#, Web e afins. Então estou num mundo novo. :)... Por isto ainda é meio complicado para mim separar o que é o Fluent API, como devo fazer os SQL e afins.

    Vamos as respostas:

    Estou fazendo minha aplicação baseado em MVC. Acho que vou partir da ideia de somente fazer um classe sem referenciar ela no banco e fazer diretamente o ValidateUser como você sugeriu. Depois vou indo para a forma mais correta.

    O cadastro pretente usar a forma normal. Não sei se no futuro terei mais casos parecidos ou em algum processamento de informações de diversos dados como irei fazer. Tipo Notas Fiscal e Itens, e guardar isto em memória e depois gravar. Isto irei pensar num futuro próximo.

    Sobre o Fluent Api, notei que ele é uma opção para o Data Annotations.
    Existe alguma opção mais simples para SQL do que o Linq? 

    Valeu pela ajuda....

    Abs




    Marlon Tiedt
    www.sesmt.com.br

    terça-feira, 5 de junho de 2012 02:36
  • Olá Marlon,
    Tudo beleza? :)

    Sim, o Fluent API é uma opção para os Data Annotations para que realmente suas classes não façam referência a nenhuma configuração, ou contexto de mapeamento.

    Existe uma opção, não mais simples, de dificuldade igual, chamada Method Based Queries... Neste caso vc terá de fazer uso de Lambdas Expressions.

    No seu caso, como vc esta começando com essa parte de acesso a dados, recomento que vc faça o MVA (Microsoft Virtual Academy) sobre Entity Framework, que é um curso online e gratuito. Assim vc entenderá como funciona a ferramenta de mapeamento objeto relacional do .Net Framework.

    Seguem dois links:

    MVA sobre Entity framework --> http://www.microsoftvirtualacademy.com/tracks/fundamentos-do-entity-framework-4

    Artigo sobre o uso de Method Based Queries --> http://msdn.microsoft.com/pt-br/library/jj128159

    []s! e bons estudos!


    Fernando Henrique Inocêncio Borba Ferreira
    while(alive){ this.WriteCode(); }
    Blog: http://ferhenriquef.com/
    Twitter: @ferhenrique

    terça-feira, 5 de junho de 2012 13:01
    Moderador
  • Como já falei valeu pela ajuda Fernando e Murilo Kunze.

    Já consegui fazer o sistema de login, e fazer o cadastro de usuário. Devagar e sempre.
    Ele está nesta url:

    http://erp.tiedt.com.br

    Agora estou vendo como personalizar as mensagens de erro de model. Já tenho, porém quero ajustar a posição.

    Abs...
    E logo logo devo estar de volta aqui...


    Marlon Tiedt
    www.sesmt.com.br

    quarta-feira, 6 de junho de 2012 01:20