0

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!

5
  • Trying newing up the navigational property in Review Constructor. Commented Sep 28, 2015 at 15:46
  • I must admit: I don't know what that means. Can you tell me how to do this? Commented Sep 28, 2015 at 15:47
  • Yeah, create a constructor on Restaurant. Google that is very simple. Then in the body add this code. Constructor Code: public Review { this.Restraunt = new Restraunt(); } Add this Above ID in Review. Commented Sep 28, 2015 at 15:49
  • 1
    In this case restaurant name will not be displayed on view. Commented Sep 28, 2015 at 15:54
  • First make sure data is there by viewing the tables in the editor. Second try to use Include from bottom answers. Third clean your solution and rebuild all then run it and see if it is fixed. Commented Sep 28, 2015 at 15:57

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

2 Comments

Semantically this is not correct. Method FindTheLatest() should not add navigation properties. It should just filter last 3 records. Include should be added before.
Both are going to yield the same results and sql. I guess it's a question as to whether you will ever want reviews without the restaurant. I wouldn't.
2

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.

3 Comments

This will work, but requires the include on every time you do this. Adding the construct is much simpler and blankets all calls.
And it is not loading data from db. But questioner want to display db data (restaurant name) on View
Kirill is correct. This is the standard way to fetch related entities. The only way to avoid it is to roll your own repository.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.