Aaron Thomas Aaron Thomas - 1 month ago 14
ASP.NET (C#) Question

Entity Framework dbSet.Add when classes linked

Question:

Why doesn't the

dbSet.Add
method work when I'm attempting to add an object that's linked to other objects in EF?

Details:

Some background on this: I'm a beginner with EF, and I'm learning how to use Code First to develop the data model.

I'm using VS2013 Express, with Entity Framework 6 added through NuGet to a basic MVC project.

I've created three classes for my data model:
Class_oneOnly
,
Class_many
, and
Class_several
.
Class_oneOnly
has a one-to-many relationship to the other two classes, and the other two classes have a many-to-many relationship to each other.

I'm using Code First, but for purposes of explaining the relationships, here's an entity relationship diagram (I drew this in a separate project, so there's no interference between Code-First and Model-First. Also, there is no pre-generated code...although perhaps I should have gone that way, I'm trying to learn Code First):

enter image description here

I can create new instances of each class.

However, when I try to perform the
DbSet.Add
method
to add a new instance of
class_many
to the database, I get an error "NullReferenceException was unhandled by user code."

This is true, I don't have this in a try-catch block. But, even with a try-catch block, it still wouldn't explain the exception:

"An exception of type 'System.NullReferenceException' occurred in EF Test Code First.dll but was not handled in user code. Additional information: Object reference not set to an instance of an object."


The main question is: Why is it that a null reference is being thrown, if all three classes at this point have been defined? Shouldn't EF take care of assigning properties to classes that are linked by relationships defined in Code First?

Should I add something to my code to make this work?

Code Examples:

Setting up the EF DbSet:

using System.Data.Entity;

namespace EF_Test_Code_First.Models
{
public class Context : DbContext
{
public Context()
: base("name=MyContext")
{
}

public DbSet<Class_many> Class_manys { get; set; }
}
}


Class definitions:

public class Class_oneOnly
{
[Key]
public string SN { get; set; }
public string Name { get; set; }

public virtual ICollection<Class_many> Class_manys { get; set; }
public virtual ICollection<Class_several> Class_severals { get; set; }
}

public class Class_several
{
public int ID { get; set; }
public string Name { get; set; }

public Class_oneOnly Class_oneOnly { get; set; }
public virtual ICollection<Class_many> Class_manys { get; set; }
}

public class Class_many
{
public int ID { get; set; }
public string Name { get; set; }

public virtual Class_oneOnly Class_oneOnly { get; set; }
public virtual ICollection<Class_several> Class_severals { get; set; }
}


...and, last but not least, my test code that sets up the classes and attempts to use DbSet.Add method.
Context dbContext
is passed from the controller (and is a static
Context
, as defined in the class above):

public void myTest(Context dbContext)
{
/* assign property values to oneOnly,
* of which there is only one of these
* in each many and each several.
*/

Class_oneOnly oneOnly = new Class_oneOnly()
{
SN = "1",
Name = "oneOnly1"
};

/* make sure ids are unique as the following
* 'for' loop is iterated through
*/
int startid;
if (dbContext.Class_manys != null && dbContext.Class_manys.Count() > 0){
startid = dbContext.Class_manys.Count();
}
else{
startid = 0;
}

/* create and fill class_many and
* class_several objects, using a new id.
*/
for (int i = startid; i < 5; i++)
{
/* assign property values to many
* and several.
*/
Class_many many = new Class_many()
{
ID = i,
Name = "many" + i.ToString()
};

Class_several several = new Class_several()
{
ID = i,
Name = "several" + i.ToString()
};

/* assign further property values
* that use navigation properties
* to link between classes.
*/
many.Class_oneOnly = oneOnly;
several.Class_oneOnly = oneOnly;
many.Class_severals.Add(several);

/* add to EF
*/
/*************************
* Error occurs at this line
*************************
*/
dbContext.Class_manys.Add(many);
}

/* save
*/
dbContext.SaveChanges();
}


I can provide code from other parts of the project on request.

Answer

Right, so I re-created your project and think I found the issue. First thing: I would recommend using your DbContext NOT as static, but rather in a using block. If you still have problems, that's what I did to try and troubleshoot, and what I always try to do. I think you will find it harder to track down problems later on if you've got a global, static context.

I hit a null reference error on many.Class_severals.Add(several); instead of where you said you did. I did use a quick Winforms project to troubleshoot, but I'm not sure why/how you would get a different error if you're using the code posted above... Anyhow, you have two options: you need to create a new collection if it's not already initialized, and you can do it in a constructor or (my preference) in the getter.

public class Class_many
    {
        public int ID { get; set; }
        public string Name { get; set; }

        private ICollection<Class_several> _severals;

        public virtual Class_oneOnly Class_oneOnly { get; set; }
        public virtual ICollection<Class_several> Class_severals { get
        {
            if (_severals == null) {_severals = new List<Class_several>();}
            return _severals;
        }
            set { _severals = value; }
        }
    }
Comments