How to create 1-N class relationships with more than one property and even subtype?

Asked

Viewed 576 times

4

I have the following class structure, unconventional but it’s in the mold that I need to solve my problem:

Tree:

public class Arvore
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

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

    public virtual ICollection<Galho_TipoA> Galhos_TipoA { get; set; }
    public virtual ICollection<Galho_TipoB> Galhos_TipoB { get; set; }
}

Twig:

public class Galho
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public int ArvoreId { get; set; }

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

    [ForeignKey("ArvoreId")]
    public Arvore Avore { get; set; }
}

public class Galho_TipoA : Galho { }
public class Galho_TipoB : Galho { }

When generating my schema I am getting the following:

CreateTable(
    "dbo.Arvores",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            Descricao = c.String(nullable: false, maxLength: 50),
        })
    .PrimaryKey(t => t.Id);
        
CreateTable(
    "dbo.Galhos",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            ArvoreId = c.Int(nullable: false),
            Descricao = c.String(nullable: false, maxLength: 50),
            Discriminator = c.String(nullable: false, maxLength: 128),
            Arvore_Id = c.Int(),
            Arvore_Id1 = c.Int(),
        })
    .PrimaryKey(t => t.Id)
    .ForeignKey("dbo.Arvores", t => t.Arvore_Id)
    .ForeignKey("dbo.Arvores", t => t.Arvore_Id1)
    .ForeignKey("dbo.Arvores", t => t.ArvoreId, cascadeDelete: true)
    .Index(t => t.ArvoreId)
    .Index(t => t.Arvore_Id)
    .Index(t => t.Arvore_Id1);

Note that various indexes are being generated for the properties of Arvore who are of the same type:

.ForeignKey("dbo.Arvores", t => t.Arvore_Id)
.ForeignKey("dbo.Arvores", t => t.Arvore_Id1)
.ForeignKey("dbo.Arvores", t => t.ArvoreId, cascadeDelete: true)
.Index(t => t.ArvoreId)
.Index(t => t.Arvore_Id)
.Index(t => t.Arvore_Id1);

I created the guys Galho_TipoA and Galho_TipoB exactly to differentiate the records by field Discriminator, but it didn’t work. Instead of pointing to ArvoreId created others, one for each property in Arvore.

How to resolve this issue to ArvoreId and not need to generate others?
Or, what would be the correct way to structure this scheme?


Editing

The need for logic that the model needs to meet is as follows: Arvore may have several Galhos of various kinds.
So I thought of the guys as separate properties.

  • I don’t quite understand what the purpose is if I can put which I improve the answer or even put another answer! I found this interesting and the effect really worked with both sides

  • It’s not easier to put the branch guy, so?

2 answers

3


The problem has not so much to do with class derivation as the fact that you have two ICollection the same base type (in this case, Galho). This creates some ambiguity when the Entity Framework assembles the sentence, as it can perfectly popular a ICollection type A with data type B, even if there is Discriminator defined.

Apparently it is not a Design flaw, but a lack of Entity Framework’s own resource. What is normally done is to accept both columns and map them with better names using the Fluent API.

  • Sorry, there is no flaw in the Entity Framework, it is based on the Normal forms, and this form that he wants doesn’t even have!

  • I wrote foul, nay glitch.

  • you cannot speak or miss, if the Entity Framework is based on normal forms should be followed like this...! it is not lacking anything! I’m sorry but you’re wrong!

2

Expected effect on the question, not a good practice, but, follow the question:

inserir a descrição da imagem aqui


[Table("Arvore")]
public class Arvore
{
    public Arvore() { }
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ArvoreId { get; set; }

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

}
public class ArvoreA : Arvore 
{
    public ArvoreA()
    {
        this.Galho = new HashSet<Galho>();
    }
    [ForeignKey("ArvoreId")]
    public virtual ICollection<Galho> Galho { get; set; }
}
public class ArvoreB : Arvore 
{
    public ArvoreB()
    {
        this.Galho = new HashSet<Galho>();
    }
    [ForeignKey("ArvoreId")]
    public virtual ICollection<Galho> Galho { get; set; }
}
[Table("Galho")]
public class Galho
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int GalhoId { get; set; }        

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

    [Required]
    public int ArvoreId { get; set; }

}
public class GalhoA : Galho 
{        
    [ForeignKey("ArvoreId")]
    public virtual Arvore Arvore { get; set; }
}
public class GalhoB : Galho 
{        
    [ForeignKey("ArvoreId")]
    public virtual Arvore Arvore { get; set; }
}

public class Context : DbContext
{
    public Context()
        :base("Con") {
            this.Configuration.ProxyCreationEnabled = true;
    }
    public DbSet<Arvore> Arvore { get; set; }
    public DbSet<Galho> Galho { get; set; }

}

using (Context ctx = new Context())
{
    //ArvoreA arvore = new ArvoreA();
    //arvore.Descricao = "Arvore 3";                
    //arvore.Galho.Add(new GalhoA() { Descricao = "Galho 3" });                
    //ctx.Arvore.Add(arvore);

    //ArvoreA arvore = ctx.Arvore.OfType<ArvoreA>().Where(x => x.ArvoreId == 1).FirstOrDefault();
    //arvore.Galho.Add(new GalhoA() { Descricao = "Galho 1" });

    ctx.SaveChanges();
}
  • Okay, @Tiagosilva

Browser other questions tagged

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