views:

147

answers:

2

I am writing an asp.net mvc application to learn Entity Framework with and am running into an issue that I do not know how to handle. For simplicity lets take the following table structure:

Movie  
ID (int, not null, auto increment)  
Name (varchar)  
GenreID (int)

and

Genre  
ID (int, not null, auto increment)  
Name (varchar)

Movie.GenreID is a FK reference to Genre.ID

I have brought across all of the tables using the visual designer in VS 2008 and tried the following Linq query:

IEnumerable<Movie> movieList = from f in dataContext.MovieSet.Include("Genre").ToList();

I can output the data in a view using:

<%= Html.Encode( movieList.Genre.Name ) %>

Everything works just fine until I have an item in the Movie table with a null GenreID. Is there something I can do to this query to make it still be able to output (just leave it blank when applicable) or am I doing something horribly wrong?

+1  A: 

The problem is that movieList.Genre is null, and you can't access the Name property of a null object.

You can solve this by writing <%= Html.Encode(movieList.Genre == null ? String.Empty : movieList.Genre.Name) %>.

If you don't want your views to be so verbose, you could add a GenreName property to the Movie entity class and move the null check there.

SLaks
Interesting that it leaves the object as null (therefore not allowing any of its properties to be accessed). I would have assumed it would have the methods all accessable with just nothing in their values. (like as if I had entered "select m.*, g.Name as GenreName from movies m left join genres g on g.ID = m.GenreID" and returned a record set I could still call GenreName and get a null response, not an exception that the join didn't take place)This removes the error but I was hoping to avoid any kind of checking in the Views.
mynameiscoffey
I agree that the "movieList.Genre.Name" syntax is very verbose but I can think of reasons I may want to be able to have that capability in the future (altho obviously there is no real need in this example, more just trying to learn what all EF/Linq is capable of doing). I noticed that if after I make a call to get my query if I add "if (movie.Genre == null) movie.Genre = new Genre();" before I return my movie object it behaves pretty much exactly as I had hoped. Is there a way to bypass the need to do a check for each property being null?
mynameiscoffey
A: 

This is probably much more readable than .Include("")

from f in dataContext.MovieSet
select new
    {
       Name = f.Name,
       Genre = f.Genre // This effectively performs a join.
       ...
    }

You can also check for the problem that way:

from f in dataContext.MovieSet
select new
    {
       Name = f.Name,
       GenreName = f.Genre == null ? "" : f.Genre.Name
       ...
    }

This gives you more flexibility, for instance:

from f in dataContext.Genres
select new
    {
        Name = f.Name
        Movies = from movie in f.Movies
                 where movie.Duration > 240
                 select movied
    }
Sander Rijken
This is very helpful as I am new to both Linq and EF. Is there a way to do a query like the ones you posted above that either return as or can be casted to the strongly typed classes that were created when I imported my table schema into EF?
mynameiscoffey
In response to your second example I also get the same effect if I were to change the "select new" section to:select new{f,Genre = (f.Genre == null) ? new Genre() : f.Genre}but I still run into the type-casting issue above.Thanks again for your response - I really appreciate the examples you gave me above.
mynameiscoffey
You can return strongly typed classes like that. The only thing you need to keep in mind is that Linq doesn't support constructors that take parameters. Instead use the object initializer syntax: `select new Movie { Name = f.Name, GenreName = f.Genre == null ? "" : g.Genre.Name };`
Sander Rijken