Casey Crookston
Casey Crookston

Reputation: 13955

Entity Framework: Loading a Linked Object

I'm not sure how to word the title of this question. I am learning Entity Framework in an MVC environment, and I am following along the Pluralsight lesson "Introduction to ASP.NET MVC 3". I've been building my solution along side the instructors, and so far, everything has gone well. But now I've hit a snag where I can't get something to work which he has working. I'll try and describe the snag:

Using Code-First, we are building a simple restaurant / review system. Here are the only two models we are using:

public class Restaurant
{
    public virtual int ID { get; set; }
    public virtual string Name { get; set; }
    public virtual string ChefsName { get; set; }
    public virtual Address Address { get; set; }
    public virtual ICollection<Review> Reviews { get; set; }

}

and

public class Review
{
    public virtual int ID { get; set; }
    public virtual Restaurant Restaurant { get; set; }
    public virtual int Rating { get; set; }
    public virtual string Body { get; set; }
    public virtual DateTime Created { get; set; }
}

You'll notice that 'Review' has a reference back to Restaurant. The database created from these models looks like this:

enter image description here

Here's the view for Review:

<div class="review">
<h4>@Model.Restaurant.Name</h4>
<span>Rating: @Model.Rating</span>
<p>
    @Model.Body
    <span class="right">
        @Html.ActionLink("Edit", "Edit", new { id = Model.ID })
    </span>
</p>

The problem I'm having is here:

@Model.Restaurant.Name

"Restaurant" comes back null, so of course a Null Reference is thrown. Here's the Index portion of the controller:

    public ActionResult Index()
    {
        var model = _db.Reviews.FindTheLatest(3);
        return View(model);
    }

And here's FindTheLatest()...

    public static IEnumerable<Review> FindTheLatest(this IQueryable<Review> reviews, int numberOfReviews)
    {
        return reviews.OrderByDescending(r => r.Created).Take(numberOfReviews);
    }

This is the query that is generated:

SELECT TOP (3) 
[Extent1].[ID] AS [ID], 
[Extent1].[Rating] AS [Rating], 
[Extent1].[Body] AS [Body], 
[Extent1].[Created] AS [Created], 
[Extent1].[Restaurant_ID] AS [Restaurant_ID]
FROM [dbo].[Reviews] AS [Extent1]
ORDER BY [Extent1].[Created] DESC

In the teacher's online example, model.Restaurant seems to come back populated, as he gets no error. Not so for me.

It seems that I have the Restaurant_ID, but I'm not sure how/when/where Entity Framework would load the Restaurant model based on that ID. There seems to be something that I missed in building my solution along side his, but I don't know what it is.

I've downloaded his solution, but I'm having a hard time getting it to compile. (See this question). Yet, I've compared his code to mine, and I can't see why his is working and mine isn't. I'm hoping someone here can help me out.

Thanks!

Upvotes: 0

Views: 306

Answers (2)

Kirill Bestemyanov
Kirill Bestemyanov

Reputation: 11964

You should use method Include:

public ActionResult Index()
{
    var model = _db.Reviews.Include(c=>c.Restaurant).FindTheLatest(3);
    return View(model);
}

This method signal to EntityFramework that it should load Restaurant navigation property with Review.

Upvotes: 2

Steve Greene
Steve Greene

Reputation: 12304

You need to include any related entities you want. Change this:

return reviews.OrderByDescending(r => r.Created).Take(numberOfReviews);

to this:

return reviews.Include(r => r.Restaurant).OrderByDescending(r => r.Created).Take(numberOfReviews);

https://msdn.microsoft.com/en-us/data/jj574232.aspx?f=255&MSPPError=-2147217396

Upvotes: 2

Related Questions