Jay
Jay

Reputation: 1033

MVC C# strange NullReference Exception

I'm getting a bit of a strange error that has left me a bit baffled, so let me paint the picture:

I have a controller that updates the database with reviews on houses. If the house doesn't exist, it creates one and then updates it.

So this is the code for if the house doesn't exist:

if (checkHouse == null)
{
        var department = db.Universitys.Single(d => d.universityName == "NotSet");//make dynamic
        var hws = new House();
        hws.address1 = reviewmodelview.Address1;
        hws.address2 = reviewmodelview.Address2;
        hws.postCode = reviewmodelview.postCode;
        hws.noOfDisputes = 0;
        department.Houses.Add(hws);
        db.SaveChanges(); //created the house and saved the changes, now apply the review to it.

        var theHouse = db.Houses.Single(d => d.address1 == reviewmodelview.Address1);//findhouse
        var rvw = new Review(); //create review
        rvw.condition = reviewmodelview.condition;
        rvw.furniture = reviewmodelview.furniture;
        rvw.overall = reviewmodelview.overall;
        rvw.isApproved = false;
        rvw.review = reviewmodelview.review;
        rvw.user = User.Identity.Name;
        rvw.reviewDate = DateTime.Now;
        theHouse.Reviews.Add(rvw);
        db.SaveChanges();
}

and here's the code for if the house does exist:

else
{
    var theHouse = db.Houses.Single(d => d.address1 == reviewmodelview.Address1);//findhouse
    var rvw = new Review();//create review
    rvw.condition = reviewmodelview.condition;
    rvw.furniture = reviewmodelview.furniture;
    rvw.overall = reviewmodelview.overall;
    rvw.isApproved = false;
    rvw.review = reviewmodelview.review;
    rvw.user = User.Identity.Name;
    rvw.reviewDate = DateTime.Now;
    theHouse.Reviews.Add(rvw);
    db.SaveChanges();
}

Now the problem is this, if the house exists, the review is added. If the house doesn't exist, the house is added to the database but the code breaks at:

theHouse.Reviews.Add(rvw); 

And if I hover my mouse over Reviews it says that its null. The error is "Object reference not set to an instance of an object."

However, if I then try again but this time add the address of a house that already exists on the database and add a breakpoint at

theHouse.Reviews.Add(rvw);

it says: {System.Data.Objects.DataClasses.EntityCollection<Data.Manager.Review>}

I can't figure out why the review collection is null for what are two identical pieces of code!

The house model is this:

namespace Data.Manager
{
    public class House
    {
        public virtual int HouseID { get; set; }
        public virtual string postCode { get; set; }
        public virtual string address1 { get; set; }
        public virtual string address2 { get; set; }
        public virtual int noOfDisputes { get; set; } //number of disputes added by tennants
        public virtual int averageRating { get; set; }
        public virtual ICollection<Review> Reviews { get; set; }        
    }
}

If I could get an explanation as to why this is happening, I'd love you forever.

Upvotes: 1

Views: 321

Answers (3)

Ant P
Ant P

Reputation: 25231

If you're creating a new house with ICollection<Review> Reviews, you will have to initialize that before you can use Reviews.Add. The reason it will work for a house that already exists will be because, when you load an existing house, the collection will be initialized and populated with the existing values.

You will have to do something along the lines of theHouse.Reviews = new List<Review>(); before you can call theHouse.Reviews.Add. You could also initialize this in advance within the constructor for House, to ensure that it is initialized prior to any access attempts.

Upvotes: 6

Muammer HALLAC
Muammer HALLAC

Reputation: 173

Try to initialize your collection of Reviews like this in House constructor

namespace Data.Manager
{
    public class House
    {
        public House()
        {
          Reviews = new List<Review>();
        }

        public virtual int HouseID { get; set; }
        public virtual string postCode { get; set; }
        public virtual string address1 { get; set; }
        public virtual string address2 { get; set; }
        public virtual int noOfDisputes { get; set; } //number of disputes added by tennants
        public virtual int averageRating { get; set; }
        public virtual ICollection<Review> Reviews { get; set; }        
    }
}

Upvotes: 2

AndrewR
AndrewR

Reputation: 6758

As the previous answer states, you need to initialize the Reviews object before adding items to it.

You can make your code slightly better by only saving the changes one time instead of making two calls to the DB.

        if (checkHouse == null)
        {

            var department = db.Universitys.Single(d => d.universityName == "NotSet");//make dynamic
            var hws = new House();
            hws.address1 = reviewmodelview.Address1;
            hws.address2 = reviewmodelview.Address2;
            hws.postCode = reviewmodelview.postCode;
            hws.noOfDisputes = 0;
            hws.Reviews = new List<Review>();

            var rvw = new Review(); //create review
            rvw.condition = reviewmodelview.condition;
            rvw.furniture = reviewmodelview.furniture;
            rvw.overall = reviewmodelview.overall;
            rvw.isApproved = false;
            rvw.review = reviewmodelview.review;
            rvw.user = User.Identity.Name;
            rvw.reviewDate = DateTime.Now;
            hws.Reviews.Add(rvw);
            department.Houses.Add(hws);

            db.SaveChanges();

        }

Upvotes: 0

Related Questions