Entity Framework 5 codefirst / Required and optional foreign key relations are null
Asked Answered
E

1

6

I'm tring to create a DbContext with my entites on entityframework5 codefirst way. I've brands, categories and products.

But when I try to get a Product it's Brand and Category fields are null. Category is optional but Brand is not. So at least the Brand field has to be setted. I tried the code below. Is there any thing that I miss?

    public DbSet<Brand> Brands { get; set; }
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Brand>()
            .HasMany(b => b.Products)
            .WithRequired(p => p.Brand)
            .HasForeignKey(p => p.BrandId);

        modelBuilder.Entity<Category>()
            .HasMany(c => c.Products)
            .WithOptional(p => p.Category)
            .HasForeignKey(p => p.CategoryId);
    }

And on MVC controller side:

    using (var db = new InonovaContext())
    {
        var product = db.Products.Single(p => p.Id == id);
        model.Description = product.Description;
        model.ImageUrl = product.ImageUrl;
        model.Name = product.Name;
        model.BreadCrumb = product.Brand.Name + " / " + product.Category == null ? "" : (product.Category.Name + " / ") + product.Name; // Here Brand and Category are null
    }

Product class is like below

public class Product
{
    public int Id { get; set; }
    public int BrandId { get; set; }
    public virtual Brand Brand { get; set; }
    public string Name { get; set; }
    public int? CategoryId { get; set; }
    public virtual Category Category { get; set; }
    public string ImageUrl { get; set; }
    public string Description { get; set; }
}

Brand class is like below:

public class Brand
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ThumbLogoImageUrl { get; set; }
    public string Description { get; set; }
    public ICollection<Product> Products { get; set; }
}

Thanks.

Endocardium answered 22/9, 2013 at 14:57 Comment(3)
What about your model classes? Did you remember to have your navigation properties defined as virtual?Bibliophile
I've updated the question with model classes. I've defined navigation properties virtual.Endocardium
No, you haven't. Navigation properties are at both ends of 1-to-many.Bibliophile
C
6

If you haven't declared the Brand and Category as virtual, lazyloading of the Brand and Category properties will not work.

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual Brand Brand { get; set; }
    public int BrandId { get; set; }

    public virtual Category Category { get; set; }
    public int? CategoryId { get; set; }
}

See this for more information on lazy and eager loading.

Carn answered 22/9, 2013 at 15:23 Comment(3)
I set the lazylaoding false and my navigation properties are virtual. Still getting null.Endocardium
I also defined the ICollection<Product> Products property on Brand as virtual and it worked. I thought that I don't have to define collections as virtual.Endocardium
All properties that are lazy loaded need to be declared virtual, also collections.Rosemarie

© 2022 - 2024 — McMap. All rights reserved.