MVC MusicStore Artist.Name Object reference not set to an instance of an object
Cracking my head while learning MVC through MVC MusicStore . Got this error for Model.Artist.Name for Details View page .
My Storecontroller Details method should be fine .
public ActionResult Details(int id)
{
//returns and albums searched from the id
var albums = storeDB.Albums.Find(id);
return View(albums);
}
And this is how I output the view
<li>Price : <%=Model.Price %></li>
<li>Artist : <%=Model.Artist.Name%></li>
Works fine for the price , and it only show error for Model.Genre.Name and Artist.Name . I am suspecting the declaration for th开发者_如何转开发ese properties in sampledata.cs caused this issue
Artist = artists.Single(a => a.Name == "Aaron Copland & London Symphony Orchestra")
But my knowledge of this is too weak to make up anything . Please help .
Alright , the value is fetched from a class file looking like this
protected override void Seed(MusicStoreEntities context)
{
var artists = new List<Artist>
{
new Artist { Name = "Aaron Copland & London Symphony Orchestra" },
etcetc
}
new List<Album>
{
new Album { Title = "ABC", Artist= artists.Single(g => g.Name == "Test")}
}
}
Take notice on how the value are being assigned , I can access Model.Title fine (where Model as the short hand) , but Model.Artist.Name caused me that error .
Solved
Alright , got it to work by adding virtual keyword to the Artist and Genre declaration in Album class . But I am still not sure what happens and would like to have anyone care to shed some lights .
In my Album class , before it is solved it looks like this
public class Album
{
public int AlbumId { get; set; }
public int GenreId { get; set; }
public int ArtistId { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public string AlbumArtUrl { get; set; }
public Genre Genre { get; set; }
public Artist Artist { get; set; }
}
The error caused by Genre and Artist is solved by adding Virtual keyword
public virtual Artist Artist { get; set; }
Somehow , I still couldn't justify what happens and wish to learn more . Anyone care to explain ?
It goes like this , Album.cs
namespace MvcMusicStore.Models
{
public class Album
{
public int AlbumId { get; set; }
public int GenreId { get; set; }
public int ArtistId { get; set; }
public string Title { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
}
using EF MusicStore.cs
namespace MvcMusicStore.Models
{
//represent entity framework , handle create ,read , update and del ops
public class MusicStoreEntities : DbContext
{
public DbSet<Album> Albums { get; set; }
public DbSet<Genre> Genres { get; set; }
public DbSet<Artist> Artists { get; set; }
}
}
and implemented in StoreController.cs
MusicStoreEntities storeDB = new MusicStoreEntities();
public ActionResult Details(int id)
{
//returns and albums searched from the id
var albums = storeDB.Albums.Find(id);
return View(albums);
}
Finally the sample data
protected override void Seed(MusicStoreEntities context)
{
var artists = new List<Artist>
{
new Artist { Name = "Aaron Copland & London Symphony Orchestra" },
etcetc
}
new List<Album>
{
new Album { Title = "ABC", Artist= artists.Single(g => g.Name == "Test")}
}
}
You are right. The error is referring to the fact that the Genre object and the Artist object has not been instantiated, and so attempting to access the Name property of either is throwing the error.
The issue is happening within the Find() method. If you are using LinqToSql, EF, NHibernate or simliar, check that your mapping is correct.
Update:
Based on the revised code, if you are doing a artists.Single(g => g.Name == "Test")
then this will would throw a NullReferenceException
if there is no Artist with the name "Test" or whatever.
I would advise doing the match on something other than a string. Use an Id to perform the match if possible. This will provide a much more reliable match condition.
Ideally you should use SingleOrDefault()
and check whether null
is returned.
It looks that Artist
or Name
is null
.
That is to say the property Artist
of Model
does not have a reference to an initialised instance of an Artist
, or a likewise scenario for Name
of an Artist
instance. You should always check for null
values prior to attempting to access an object:
if (Model.Artist != null)
{
//do something with artist
}
The same explanation would stand for other properties, such as Genre
, too.
Curiously, though, is that the use of Single
to get only an individual entity ought to throw an exception if no Artist
satisfies the query (or more than one of such satisfies) - is this your exact code, or a test that the Artist
you want does actually exist?
Alright , got it to work by adding virtual keyword to the Artist and Genre declaration in Album class . But I am still not sure what happens and would like to have anyone care to shed some lights .
See above .
GenreId,ArtistId and AlbumId cannot be null example:
public int? GenreId { get; set; }
精彩评论