Inheritance with Entity Framework

Asked

Viewed 232 times

2

I have a doubt in the inheritance part, I have the person and user classes. Person has its basic attributes and the user inherits from the person. So far so good is right.

My problem is that in context mapping I am passing the user, but I would not like you to create all fields of the person in the database, so how can I limit which fields I want to be created in the database ? or there is no way.

Classe Pessoa

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;


namespace Model
{
    public class Pessoa
    {
        private int codigo;
        private int status; // Ativo = 1, Inativo = 0
        private string nome;
        private string email;
        private string cidade;
        private string endereco;
        private string bairro;
        private string numero;
        private DateTime dtCriacao;

        //Contrutor para heranca para obrigacao da criacao de usuario
        public Pessoa( string nome, string email, int status) {
            this.nome  = nome;
            this.email = email;
            this.status = status;
            this.dtCriacao = DateTime.Now;
        }

        [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
        [Required(AllowEmptyStrings = false, ErrorMessage = "Data Criaçao deve estar preenchida")]
        public DateTime DtCriacao
        {
            get { return dtCriacao; }
            set { dtCriacao = value; }
        }


        [Key]
        public int Codigo
        {
            get { return codigo; }
            set { codigo = value; }
        }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Status deve estar entre 1 = Ativo ou 0 = Inativo")]
        [Range(0, 1)]
        public int Status
        {
            get { return status; }
            set { status = value; }
        }

        [StringLength(15)]
        public string Numero
        {
            get { return numero; }
            set { numero = value; }
        }

        [StringLength(80)]
        public string Bairro
        {
            get { return bairro; }
            set { bairro = value; }
        }

        [StringLength(100)]
        public string Endereco
        {
            get { return endereco; }
            set { endereco = value; }
        }

        [StringLength(100)]
        public string Cidade
        {
            get { return cidade; }
            set { cidade = value; }
        }

        [Required(AllowEmptyStrings = false, ErrorMessage = "E-mail deve estar preenchido")]
        [StringLength(250)]
        [EmailAddress(ErrorMessage = "E-mail em formato inválido.")]
        public string Email
        {
            get { return email; }
            set { email = value; }
        }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Nome deve ser preenchido")]
        [StringLength(200)]
        public string Nome
        {
            get { return nome; }
            set { nome = value; }
        }


    }
}

User class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Model
{
    [Table("Usuario", Schema = "public")]
    public class Usuario : Pessoa
    {
        private string login;
        private string senha;

        public Usuario(string nome, string email, int status, string login, string senha) : base( nome, email, status)
        {
            this.login = login;
            this.senha = senha;

        }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Login deve ser preenchido!")]
        [StringLength(50)]
        [Index("Ix_UsuarioLogin", IsUnique = true)]
        public string Login
        {
            get { return login; }
            set { login = value; }
        }

        [Required(AllowEmptyStrings = false, ErrorMessage = "Senha deve ser preechida!")]
        [StringLength(20)]
        public string Senha
        {
            get { return senha; }
            set { senha = value; }
        }

    }
}

Context

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Npgsql;
using System.Data.Entity;
using Model;
namespace DAL
{

        public class BaseContexto : DbContext
        {
            public BaseContexto()
                : base("Teste")
            { }

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.HasDefaultSchema("public"); base.OnModelCreating(modelBuilder);
            }

            public DbSet<Usuario> Usuario { get; set; }
        }

}

My problem is here, in the table was created the address data I do not need, type city, address, number... How can I get this data not to be mapped?

My user table:

CREATE TABLE public."Usuario"
(
  "Codigo" integer NOT NULL DEFAULT nextval('"Usuario_Codigo_seq"'::regclass),
  "Login" character varying(50) NOT NULL DEFAULT ''::character varying,
  "Senha" character varying(20) NOT NULL DEFAULT ''::character varying,
  "DtCriacao" timestamp without time zone NOT NULL DEFAULT '-infinity'::timestamp without time zone,
  "Status" integer NOT NULL DEFAULT 0,
  "Numero" character varying(15),
  "Bairro" character varying(80),
  "Endereco" character varying(100),
  "Cidade" character varying(100),
  "Email" character varying(250) NOT NULL DEFAULT ''::character varying,
  "Nome" character varying(200) NOT NULL DEFAULT ''::character varying,
  CONSTRAINT "PK_public.Usuario" PRIMARY KEY ("Codigo")
)
WITH (
  OIDS=FALSE
);
ALTER TABLE public."Usuario"
  OWNER TO postgres;

-- Index: public."Usuario_Ix_UsuarioLogin"

-- DROP INDEX public."Usuario_Ix_UsuarioLogin";

CREATE UNIQUE INDEX "Usuario_Ix_UsuarioLogin"
  ON public."Usuario"
  USING btree
  ("Login" COLLATE pg_catalog."default");

2 answers

2


first, if Usuario should not have all fields of Pessoa, soon he should not inherit from person.

In your case, the most interesting approach is to make a 1-1 relationship with Usuario and Pessoa, but you would end up with the same problem you mentioned.

Your second option is to create an abstract class that serves as the basis for User and Person.:

public abstract class PessoaBase
{       
    //Contrutor para heranca para obrigacao da criacao de usuario
    public PessoaBase(string nome, string email, int status) {
        this.nome  = nome;
        this.email = email;
        this.status = status;
        this.dtCriacao = DateTime.Now;
    }

    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Data Criaçao deve estar preenchida")]
    public DateTime DtCriacao { get; set; }

    [Key]
    public int Codigo { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Status deve estar entre 1 = Ativo ou 0 = Inativo")]
    [Range(0, 1)]
    public int Status { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "E-mail deve estar preenchido")]
    [StringLength(250)]
    [EmailAddress(ErrorMessage = "E-mail em formato inválido.")]
    public string Email { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Nome deve ser preenchido")]
    [StringLength(200)]
    public string Nome { get; set; }
}

[Table("Pessoa", Schema = "public")]
public class Pessoa : PessoaBase
{
    public Pessoa()
    {

    }

    [StringLength(15)]
    public string Numero { get; set; }

    [StringLength(80)]
    public string Bairro { get; set; }

    [StringLength(100)]
    public string Endereco { get; set; }

    [StringLength(100)]
    public string Cidade { get; set; }
}

[Table("Usuario", Schema = "public")]
public class Usuario : PessoaBase
{
    public Usuario()
    {

    }

    public Usuario(string nome, string email, int status, string login, string senha) : base( nome, email, status)
    {
        this.login = login;
        this.senha = senha;
    }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Login deve ser preenchido!")]
    [StringLength(50)]
    [Index("Ix_UsuarioLogin", IsUnique = true)]
    public string Login { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Senha deve ser preechida!")]
    [StringLength(20)]
    public string Senha{ get; set; }
}

your third option, is to add a metadata class to Usuario.

[Table("Pessoa", Schema = "public")]
public class Pessoa
{
    public Pessoa()
    {

    }

    //Contrutor para heranca para obrigacao da criacao de usuario
    public Pessoa(string nome, string email, int status) {
        this.nome  = nome;
        this.email = email;
        this.status = status;
        this.dtCriacao = DateTime.Now;
    }

    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Data Criaçao deve estar preenchida")]
    public DateTime DtCriacao { get; set; }

    [Key]
    public int Codigo { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Status deve estar entre 1 = Ativo ou 0 = Inativo")]
    [Range(0, 1)]
    public int Status { get; set; }

    [StringLength(15)]
    public string Numero { get; set; }

    [StringLength(80)]
    public string Bairro { get; set; }

    [StringLength(100)]
    public string Endereco { get; set; }

    [StringLength(100)]
    public string Cidade { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "E-mail deve estar preenchido")]
    [StringLength(250)]
    [EmailAddress(ErrorMessage = "E-mail em formato inválido.")]
    public string Email { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Nome deve ser preenchido")]
    [StringLength(200)]
    public string Nome { get; set; }
}

[Table("Usuario", Schema = "public")]
[MetadataType(typeof(UsuarioMetadata))]
public class Usuario : Pessoa
{
    public Usuario()
    {

    }

    public Usuario(string nome, string email, int status, string login, string senha) : base( nome, email, status)
    {
        this.login = login;
        this.senha = senha;
    }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Login deve ser preenchido!")]
    [StringLength(50)]
    [Index("Ix_UsuarioLogin", IsUnique = true)]
    public string Login { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessage = "Senha deve ser preechida!")]
    [StringLength(20)]
    public string Senha{ get; set; }
}

public class UsuarioMetadata
{
    [NotMapped]
    public string Numero { get; set; }

    [NotMapped]
    public string Bairro { get; set; }

    [NotMapped]
    public string Endereco { get; set; }

    [NotMapped]
    public string Cidade { get; set; }
}
  • Okay I understand, thanks for the answer I will use the abstract class. Only one doubt that has arisen, the inheritance should only be used when the child class will use all attributes of the parent class?

  • 1

    @Apprentice if the parent class has unwanted properties in the daughter class, then this distorts inheritance and possibly points to a problem in modeling.

  • Read about the Interface Segregation Principle, which corresponds to the letter "I" of SOLID: https://robsoncastilho.com.br/2013/04/14/principios-solid-principio-segregaca-de-interface-isp/

  • Thank you, just one other thing, I can inherit an Abstract class by creating another Abstract? class or it’s wrong. Example: public abstract class PessoaBase{}&#xA; public abstract class Pessoa : PessoaBase {}&#xA;&#For the class person also should not be instantiated in my system, only inherited.

  • 1

    @Apprentice, an abstract class is still a class, has no problem in it inherits from another class, whether abstract or not.

1

An alternative implementation for your case would be to create a mapping class and use the Ignore for properties you don’t want to map to the bank:

Mapping class:

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

namespace SOpt.Entity
{
    public class UsuarioMapeamento : EntityTypeConfiguration<Usuario>
    {
        public UsuarioMapeamento()
        {
            HasKey(u => u.Codigo).Property(x => x.Codigo).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(u => u.Login);
            Property(u => u.Senha);
            Property(u => u.DtCriacao);
            Property(u => u.Status);
            Property(u => u.Email);
            Property(u => u.Nome);

            Ignore(u => u.Numero);
            Ignore(u => u.Bairro);
            Ignore(u => u.Endereco);
            Ignore(u => u.Cidade);
        }
    }
}

In your context class, you will need to remove the line public DbSet<Usuario> Usuario { get; set; }, adding the new mapping class in the settings of the ModelBuilder:

using System.Data.Entity;

namespace SOpt.Entity
{
    public class BaseContexto : DbContext
    {
        public BaseContexto()
                : base("connectionstring")
        { }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema("public");

            modelBuilder.Configurations.Add(new UsuarioMapeamento());

            base.OnModelCreating(modelBuilder);
        }
    }
}

Script generated by Entity using this implementation:

IF schema_id('public') IS NULL
    EXECUTE('CREATE SCHEMA [public]')
CREATE TABLE [public].[Usuario] (
    [Codigo] [int] NOT NULL IDENTITY,
    [Login] [nvarchar](50) NOT NULL,
    [Senha] [nvarchar](20) NOT NULL,
    [DtCriacao] [datetime] NOT NULL,
    [Status] [int] NOT NULL,
    [Email] [nvarchar](250) NOT NULL,
    [Nome] [nvarchar](200) NOT NULL,
    CONSTRAINT [PK_public.Usuario] PRIMARY KEY ([Codigo])
)
CREATE UNIQUE INDEX [Ix_UsuarioLogin] ON [public].[Usuario]([Login])
CREATE TABLE [public].[__MigrationHistory] (
    [MigrationId] [nvarchar](150) NOT NULL,
    [ContextKey] [nvarchar](300) NOT NULL,
    [Model] [varbinary](max) NOT NULL,
    [ProductVersion] [nvarchar](32) NOT NULL,
    CONSTRAINT [PK_public.__MigrationHistory] PRIMARY KEY ([MigrationId], [ContextKey])
)
INSERT [public].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
VALUES (N'201704061249317_Inicial', N'SOpt.Entity.Migrations.Configuration',  0x1F8B0800000000000400CD58DB6EE336107D2FD07F10F4EC356307055A43DA45D64E0AA3B961E5EC6B414B639B28456A452AB0B1E897F5A19FD45FE848A2EEB66CC7BB68919768C4393C339C391CF99FBFFE763E6C436EBD42AC9814AE3D1A5ED916085F064CAC5D3BD1AB773FDB1FDEFFF883731B845BEB73B1EE3A5D879E42B9F646EB684288F2371052350C991F4B25577AE8CB90D04092F1D5D52F643422801036625996F329119A85903DE0E3540A1F229D50FE2003E0CAD8F18D97A15A8F340415511F5CDB7B8AF4F016DDF5CEB66E38A348C103BEB22D2A84D45423C1C98B024FC752ACBD080D942F7611E0BA15E50A0CF149B5FCD418AEC6690CA4722CA0FC4469199E0938BA3649216DF737A5D62E938669CBF393469DA5CEB55F544263266DABBDD764CAE3745D23B143B37C60D58C83F2F8B14AD2BF81354DB84E627005243AA67C603D274BCEFCDF60B7907F807045C2799D1732C3770D039A9E631941AC779F6065D84EB1FED64896347D49DBB9746DF9E501CD85BE1EDBD62392A04B0EE5F1D782F7B48CE1571010530DC133D51A623CBD7900A6C048EF7EF772CD44B11D161C368D6D3DD0ED3D88B5DEB8F64FD825776C0B4161300C5E04C316431F1D27B08761FFAE1E880DEDD975FC5D769DE969CCA84FCBF4CE30650B6CE2F3F963F21375EC94FA316E43CA785F0EBE4FEA1F651A6F4FE6BFC1AE0EA9BAB7DBD328959A322C58C3E8235590DA60ABF775370AA1697065366FC697837AA09B3A81A75391C8F575584AC83EB225AD4ABA49AEDD85C6930322EF3CD028C244D644DF582C2F57FCE93BEF7C450C730CE2AB3DC258B22D77421DA06B68BDCD0405EE58AC34163B5DD2F4A8A641D859D6388403092EB66AE5B92D8655DA0B87F47FD3385D856EFB57D9BBC3804294B12C362869545741C733BB6E29A7F101559D4A9E84A24FA1FB508C56D6418CE9740CA37C750C633A1DA3A663759C9AF90C3E46C91A848CED7414A3657510633A1D2317A63A446EE92238A45520ED0A249D126CDDC2ED92EE9383F69272F752165AEDEF98563C3E08767A335F625B989A5716A47DE9ED948670982E187A5FF894338CB75AF040055B81D2F9B082EA3D1AB746CAFFCF7847940AF86933DE7F3670B134B94747AA33AFDCC68C255E69EC6F68BCE7A69B8B00B6AEFD35739B58F3EDEF261F19C0C09A2BBC84BF24F86A81D7A0F5676750BB640AAB78B5E6B04B87AC0093A82F1FB2B293B964C4DA1FE01BD2569FA00E64ED18E8790352F70A3F6902EA1B8072A171ED28FBDAC16872AA970E485DE57348FD43D9998162EB0A22FD6C16E0A7D55F81166BE662258BD463707546C592D6C93C80A6586EF426D66C457D8DAF7D502A9B713F539E6425B184602E9E121D25FA46290897BCF191E490FEFDB329B0C9D9C1A1069FD4B7080169B2B4639EC4C784F1A0E47DB7A7880E40A4E562D40B59E18C8F70EB5D89F428C58940267D338840A4DAB78030E208A69E84475FE12DDC7098BF8735F577C5057618E4F84134D3EECC185DC7345406A3F24F7FFC21E9AF3FEFFF0550235FB82F120000 , N'6.1.3-40302')

Browser other questions tagged

You are not signed in. Login or sign up in order to post.