Jacob Humlinski
Jacob Humlinski

Reputation: 13

ASP.Net Passing Object To View With A Parameter Set To A List of Another Object Filtered By Matching IDs

I'm currently working in ASP.NET with Entity Framework and I am dealing with two model objects, called "Game" and "Review".

"Review" has a property called "GameId"

"Game" has a property called "Reviews" which is an ICollection intended to hold a collection of "Review" where "GameId" matches the "Game"s "Id".

I am in the "GamesController" trying to pass a "Game" to the "Detail" view where the details of "Game" will be displayed, including the list of "Review" that match.

This is my current code.

///Controller Code///
public ActionResult Details(int? id)
{    
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    Game game = db.Games.Find(id);

    game.Reviews = db.Reviews.ToList().Where(r => r.GameId == game.Id) as ICollection<Review>;

    if (game == null)
    {
        return HttpNotFound();
    }

    return View(game);
}
///End Controller Code///


///View Code///
@model GameReviewApp.Models.Game

//snipped irrelevant code//

@foreach (var item in Model.Reviews)
{
    <p>@item.Content</p>
}

///End View Code///

When running this code I get the following error when i try to load up the "Detail" page and display the list of "Review"

System.NullReferenceException: 'Object reference not set to an instance of an object.'

From what I can see, after my LINQ filter, the ICollection isn't getting populated and it's being left null. I've double checked my database and I know there are 2 entries that should end up in the list were the filter to work properly. Any advice?

Upvotes: 1

Views: 65

Answers (3)

Ali Umair
Ali Umair

Reputation: 1424

If games and reviews have a proper relationship defined, it should have been loaded by lazyloading and you don't need the second query.Otherwise just put a null check after this

Game game = db.Games.Find(id);

if (game != null)
{
    game.Reviews = db.Reviews.Where(r => r.GameId == game.Id).ToList();
}

Upvotes: 0

surendra
surendra

Reputation: 1

you need to initialize game.Reviews

    objGame.Reviews = new Icollection<Review>();
    //or

    Game objGame= new Game(){
    Reviews=new ICollection<Review>()
    };

Upvotes: 0

sbsd
sbsd

Reputation: 306

The problem is that you're trying to cast the IEnumerable returned by LINQ to an ICollection - because the cast fails, game.Reviews will be null every time.

The below code should work for you:

public ActionResult Details(int? id)
    {    
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        Game game = db.Games.Find(id);

        if (game == null)
        {
            return HttpNotFound();
        }

        game.Reviews = db.Reviews.Where(r => r.GameId == game.Id).ToList();            

        return View(game);
    }

You can use .ToList() instead of as ICollection<Review>, which should successfully achieve what you're going for.

I'd also recommend removing the .ToList() from db.Reviews.ToList(), as it retrieves every Review from the database and puts them in memory, and here you're only interested in Reviews with a matching GameId.

EDIT: As has been mentioned, your nullcheck for game should also come immediately after resolving the object.

Upvotes: 0

Related Questions