Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to guarantee consistent code with derived fields using entity framework

I have the following Classes/Tablesenter image description here

Apolices.CodRamos is in that table just because it is a Key. Apolices.CodRamo must be equal to Apolices.CodProduto.CodRamo to keep the code consistent.

I thought I could solve this issue having this in my Apolices Model class:

public int CodRamo
    {
        get{ return Produtos.CodRamo; }
        set{ Produtos.CodRamo = value; }
    }

public virtual Produtos Produtos { get; set; }

But this does not work beacuse of the way the class is loaded since it tries to use the virtual field when is not initialised yet.

And if I create a new Produtos it messes up the CodProduto relationship. Produto.CodProduto stays equal to 0 all the time...

How can I solve this to have consistent code?

edit: Bellow the complete code:

public partial class Apolices
{
    [Key]
    [Column(Order = 0)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CodApolice { get; set; }

    [Key]
    [Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CodRamo
    {
        get{ return Produtos.CodRamo; }
        set{ Produtos.CodRamo = value; }
    }

    [StringLength(50)]
    public string Descricao { get; set; }

    public int? CodProduto { get; set; }

    public virtual Produtos Produtos { get; set; }

    public virtual Ramos Ramos { get; set; }
}


public partial class Produtos
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Produtos()
    {
        Apolices = new HashSet<Apolices>();
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CodProduto { get; set; }

    public int CodRamo { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Apolices> Apolices { get; set; }

    public virtual Ramos Ramos { get; set; }
}


public partial class Ramos
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Ramos()
    {
        Apolices = new HashSet<Apolices>();
        Produtos = new HashSet<Produtos>();
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CodRamo { get; set; }

    [StringLength(50)]
    public string Descricao { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Apolices> Apolices { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Produtos> Produtos { get; set; }
}

public partial class ModelContext : DbContext
{
    public ModelContext()
        : base("name=ModelContext")
    {
    }

    public virtual DbSet<Apolices> Apolices { get; set; }
    public virtual DbSet<Produtos> Produtos { get; set; }
    public virtual DbSet<Ramos> Ramos { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Apolices>()
            .Property(e => e.Descricao)
            .IsUnicode(false);

        modelBuilder.Entity<Ramos>()
            .Property(e => e.Descricao)
            .IsUnicode(false);

        modelBuilder.Entity<Ramos>()
            .HasMany(e => e.Apolices)
            .WithRequired(e => e.Ramos)
            .WillCascadeOnDelete(false);
    }
}
like image 555
RagnaRock Avatar asked Mar 26 '26 09:03

RagnaRock


2 Answers

The problem there is that you are trying to make a relationship between Apolice, Produtos, and Ramos. However, considering your explanation, what you are really want to make is a relationship between Apolice, RelationshipOfProdutosRamos. So, the table structure should be something like this:

enter image description here

SQL Code:

create table Produtos (
    CodProduto int primary key not null identity(1,1),
    Descricao varchar(50) not null
)

create table Ramos (
    CodRamo int primary key not null identity(1,1),
    Descricao varchar(50) not null
)

create table ProdutosRamos (
    CodProduto int not null foreign key references Produtos(CodProduto),
    CodRamo int not null foreign key references Ramos (CodRamo),
    primary key (CodProduto, CodRamo)
)

create table Apolices (
    CodProduto int not null,
    CodRamo int not null,
    Descricao varchar(50) not null,
    primary key (CodProduto, CodRamo),
    foreign key (CodProduto, CodRamo) references ProdutosRamos (CodProduto, CodRamo)
)

Then, you have to make some changes in EntityFramework:

public partial class Apolices
{
    [Key]
    [Column(Order = 0)]
    [ForeignKey("ProdutosRamos")]
    public int CodProduto { get; set; }

    [Key]
    [Column(Order = 1)]
    [ForeignKey("ProdutosRamos")]
    public int CodRamo
    {
        get; set;
    }

    [StringLength(50)]
    public string Descricao { get; set; }

    public virtual ProdutosRamos ProdutosRamos { get; set; }
}


public partial class Produtos
{  
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CodProduto { get; set; }

    [StringLength(50)]
    public string Descricao { get; set; }
}


public partial class Ramos
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CodRamo { get; set; }

    [StringLength(50)]
    public string Descricao { get; set; }
}

public partial class ProdutosRamos
{  
    [Key]
    public int CodProduto { get; set; }

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

    [ForeignKey("CodProduto")]
    public virtual Produtos Produtos { get; set; }

    [ForeignKey("CodRamo")]
    public virtual Ramos Ramos { get; set; }
}

Hope it helps!

like image 123
Fabio Luz Avatar answered Mar 27 '26 21:03

Fabio Luz


The problem is that the database is not in normal form (and does not reflect what you are describing).

Navigating from Apolices to Produtos you can have more Apolices records for a single Produtos record. Think about the table Apolices, fixing a single CodApolice (i.e. AP1) you can have (in 3 different records) CodRamo R1, CodRamo R2 and CodRamo R3 everyone with the same P1 CodProduto. So the single Productos can have more than one Ramo.
Also, the single Produto is associated with more than Apolices with the code A1 (the pk of Apolices table is CodApolice and CodRamo). Is this ok?
And so on...

like image 45
bubi Avatar answered Mar 27 '26 22:03

bubi