EF6 NullReferenceException with any ToList()

7

Using C#, .NET 4.5.2, Entity Framework 6.1.3 and System.Linq I have encountered a confusing exception. The exception itself does not seem to contain useful information to determined why it is being raised.

The following line of code when executed results in a NullReferenceException: dbCtx.Customers.ToList();

However, the following line runs without exception and returns the correct result: (dbCtx.Customers).ToList();

Running the parenthesis surrounded expression first will allow both forms to execute without exception:

var result1 = (dbCtx.Customers).ToList();
var result2 = dbCtx.Customers.ToList();

I would also like to note that adding entities works as expected:

dbCtx.Customers.Add(new Customer() { Enabled = true, Name = "Test" });

Customer entity class:

public sealed class Customer : BaseEntity
{
    public bool Enabled { get; set; }

    [Required]
    public string Name { get; set; }
}

BaseEntity class:

public abstract class BaseEntity
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
}

DbContext class:

public class MyDbContext : DbContext
{
    public MyDbContext() : base(@"Server=.\SQLExpress;Database=MyDatabase;Trusted_Connection=Yes;")
    {
        Configuration.LazyLoadingEnabled = true;
    }

    public virtual DbSet<Customer> Customers { get; set; }
}

What could possibly be causing this behavior?

EDIT: This problem occurs with any entity when anything like .ToList(), .Count(), etc is invoked.

Exception Details:

System.NullReferenceException occurred
    HResult=0x80004003
    Message=Object reference not set to an instance of an object.
    Source=EntityFramework
    StackTrace:
      at System.Data.Entity.Internal.Linq.InternalSet`1.get_Expression()
      at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Expression()
      at MyProjTests.Test1.Test(MyDbContext dbCtx) in E:\ProgrammingProjects\WorkInProgress\MyProjRoot\MyProjTests\Test1.cs:line 51
      at MyProjTests.Test1.TestMethod1() in E:\ProgrammingProjects\WorkInProgress\MyProjRoot\MyProjTests\Test1.cs:line 43

EDIT 2:

After experimentation I've narrowed it down to a call to dbCtx.Database.CompatibleWithModel(bool). Whether the argument supplied is true or false makes no difference. When I commented it out no NullReferenceException is raised later in the code. I have no idea why. Calling dbCtx.Database.Exists() works fine. In addition, dbCtx.Database.Initialize(false); Also reliably produces the error (not at callsite, but on xyz.ToList()).

c#
entity-framework-6
nullreferenceexception
asked on Stack Overflow Jun 21, 2017 by Ben Manning • edited Jun 22, 2017 by Ben Manning

2 Answers

0

For all I know the two expressions (with and without brackets) are absolutely equivalent and cannot possibly cause a different behavior. You can check that by looking at the IL code generated (here's how: A tool for easy IL code inspection). In obscure cases like this, I would generally suspect some form of multithreading to be the culprit. Try isolating the offending code to the bare minimum and see if you can still reproduce this.

answered on Stack Overflow Jun 21, 2017 by dnickless
0

I have found a resolution. As best as I can tell, it is caused when certain methods like Database.Initialize() and Database.CompatibleWithModel() are called from outside the scope of a InitializeDatabase() method of a child of IDatabaseInitializer. Perhaps there is some unknown side effect involved with those methods..?

I'll include an example specialization of IDatabaseInitializer just for clarity for anyone else who may stumble across this problem:

public class CreateOrMigrateDatabaseInitializer<TContext, TConfiguration>
    : CreateDatabaseIfNotExists<TContext>, IDatabaseInitializer<TContext>
    where TContext : DbContext
    where TConfiguration : DbMigrationsConfiguration<TContext>, new()
{

    void IDatabaseInitializer<TContext>.InitializeDatabase(TContext context)
    {
        if (context.Database.Exists())
        {
            if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false))
            {
                var migrationInitializer = new MigrateDatabaseToLatestVersion<TContext, TConfiguration>(true);
                migrationInitializer.InitializeDatabase(context);
            }
        }

        base.InitializeDatabase(context);
    }
}
answered on Stack Overflow Jun 22, 2017 by Ben Manning

User contributions licensed under CC BY-SA 3.0