Reputation: 623
I have this Product class for an order taking restaurant application:
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public virtual ICollection<ServingChoice> ServingChoices { get; set; }
}
A product may have a choice of serving, like 'Soup of the Day' offers the user the choice of choosing among a few products.
Both the Product and Choices are both of type Product
:
public class ServingChoice
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ProductId { get; set; }
public int ChoiceId { get; set; }
public Product Product { get; set; }
[InverseProperty("ServingChoices")]
public Product Choice { get; set; }
}
I am doing something wrong, since a Product never loads its choices. The table seems to be created correctly.
It looks like kinda works, but inversed. If I manually ad into the database some records, like this:
ProductID | ChoiceID
1 10
2 10
3 10
it works for the Product with Id=10.
Upvotes: 2
Views: 522
Reputation: 39376
I think your problem is because you are not mapping the FKs as you should. Try this:
public class ServingChoice
{
//...
[ForeignKey("Product")]
public int ProductId { get; set; }
[ForeignKey("Choice")]
public int ChoiceId { get; set; }
public Product Product { get; set; }
[InverseProperty("ServingChoices")]
public Product Choice { get; set; }
}
BTW, you are configuring two one-to-many relationships, but in the relationship where is involve the Product
navigation property (in the ServingChoice
class) you are not defining the other end. If you want to do that, you should declare another navigation property in the Product
entity:
public class Product
{
[Key]
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)] this is not necessary, it's the default behavior
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public virtual ICollection<ServingChoice> ProductChoices { get; set; }
public virtual ICollection<ServingChoice> ServingChoices { get; set; }
}
Then, in the ServiceChoice
class you should add the InverseProperty
annotation on the Product
navigation property to specify explicitly what is the other end of the relationship:
public class ServingChoice
{
[Key]
// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] the same I explain before
public int Id { get; set; }
[ForeignKey("Product")]
public int ProductId { get; set; }
[ForeignKey("Choice")]
public int ChoiceId { get; set; }
[InverseProperty("ProductChoices")]
public Product Product { get; set; }
[InverseProperty("ServingChoices")]
public Product Choice { get; set; }
}
Also, you can use Fluent Api following the same idea:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ServingChoice>().HasRequired(m => m.Product).WithMany(m => m.ProductChoices).HasForeignKey(m=>m.ProductId);
modelBuilder.Entity<ServingChoice>().HasRequired(m => m.Choice).WithMany(m => m.ServingChoices).HasForeignKey(m=>m.ChoiceId);
}
Upvotes: 1