简体   繁体   English

任何ToList()的EF6 NullReferenceException

[英]EF6 NullReferenceException with any ToList()

Using C#, .NET 4.5.2, Entity Framework 6.1.3 and System.Linq I have encountered a confusing exception. 使用C#,.NET 4.5.2,Entity Framework 6.1.3和System.Linq我遇到了一个令人困惑的异常。 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(); 执行时的以下代码行导致NullReferenceException: dbCtx.Customers.ToList();

However, the following line runs without exception and returns the correct result: (dbCtx.Customers).ToList(); 但是,以下行无例外地运行并返回正确的结果: (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: BaseEntity类:

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

DbContext class: DbContext类:

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. 编辑:当调用.ToList(),. Count()等任何实体时,任何实体都会出现此问题。

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: 编辑2:

After experimentation I've narrowed it down to a call to dbCtx.Database.CompatibleWithModel(bool) . 经过实验,我把它缩小到对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. 当我评论它时,代码中不会引发NullReferenceException。 I have no idea why . 我不明白为什么 Calling dbCtx.Database.Exists() works fine. 调用dbCtx.Database.Exists()工作正常。 In addition, dbCtx.Database.Initialize(false); 另外, dbCtx.Database.Initialize(false); Also reliably produces the error (not at callsite, but on xyz.ToList()). 还可靠地产生错误(不是在callsite,而是在xyz.ToList()上)。

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 ). 您可以通过查看生成的IL代码来检查(这里是如何: 一个简单的IL代码检查工具 )。 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. 尝试将有问题的代码隔离到最低限度,看看你是否仍然能够重现这一点。

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 . 据我所知,当从IDatabaseInitializer的子类的InitializeDatabase()方法的范围之外调用某些方法(如Database.Initialize()Database.CompatibleWithModel()时,会导致这种情况。 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: 我将包含IDatabaseInitializer的示例专门化,仅为了清楚可能偶然发现此问题的其他人:

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM