3

I have been attempting to use EF Code First to create and manage my Database for a project I am working on. I have, however, encountered a slight issue.

public class Planet
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    [Required]
    public string Planet_Name { get; set; }
    [Required]
    public int Planet_X { get; set; }
    [Required]
    public int Planet_Y { get; set; }
    [Required]
    public string Planet_Desc { get; set; }
    public virtual ICollection<Mineral> Minerals { get; set;}
}

public partial class Mineral
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Symbol { get; set; }
    [Required]
    public string Mineral_Desc { get; set; }
    [Required]
    public int rate { get; set; }
    [Required]
    public decimal ratio { get; set; }
}

When using the above, The Mineral table acquires a Planet_Id Column Set as a ForeignKey. This, of course, has the side-effect of causing an error to be thrown when 2 planet have the same mineral. What I need is to allow multiple planets to share a Mineral. While the Planet needs to know what Minerals it has, the Mineral has no reason to know what Planets it is on.

My question therefore is, how do I go about doing that? (Note: I have attempted to add a public virtual Planet to the Mineral class, it changes nothing.)

Simon Karlsson
  • 4,090
  • 22
  • 39
LordVe
  • 51
  • 1
  • 6
  • You need a many-to-many relation ship; there are many tutorials, for example, [here](https://msdn.microsoft.com/en-us/data/jj591620#ManyToMany) – Peter Smith Feb 01 '16 at 08:16

1 Answers1

1

you need to add a ICollection<Planet> Planets in your Mineral class :

public class Mineral
{
    public Mineral()
    {
        Planets = new HashSet<Planet>();
    }

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Symbol { get; set; }
    [Required]
    public string Mineral_Desc { get; set; }
    [Required]
    public int rate { get; set; }
    [Required]
    public decimal ratio { get; set; }

    public virtual ICollection<Planet> Planets { get; set; }        
}

Also in your Planet class, you should add a default constructor :

public class Planet
{
    public Planet()
    {
        Minerals = new HashSet<Mineral>();
    }

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    [Required]
    public string Planet_Name { get; set; }
    [Required]
    public int Planet_X { get; set; }
    [Required]
    public int Planet_Y { get; set; }
    [Required]
    public string Planet_Desc { get; set; }

    public virtual ICollection<Mineral> Minerals { get; set; }
}

So In your DbContext, you need to define both entity Planet and Mineral and create a many to many relation by overriding the OnModelCreating function:

public class PlanetContext : DbContext
{
    public DbSet<Planet> Peoples { get; set; }

    public DbSet<Mineral> Minerals { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Planet>()
            .HasMany(p => p.Minerals)
            .WithMany(m => m.Planets)
            .Map(t => t.MapLeftKey("PlanetID")
                .MapRightKey("MineralID")
                .ToTable("PlanetMineral"));
    }
}
Thomas
  • 24,234
  • 6
  • 81
  • 125
  • That works, and I thank you. A bit of a sub-question: Is there a way to prevent my code from becoming bloated with Relationship Properties? I can think of at least 3 other classes that will use Minerals. – LordVe Feb 01 '16 at 22:00
  • You will always have to define many-to-many relationship using EF. Have a look at the EF Convention https://msdn.microsoft.com/en-nz/data/jj679962.aspx. Otherwise, I am not sure you have to specify the .Map part of the configuration. – Thomas Feb 01 '16 at 22:23