2017-06-21 40 views
7

使用C#,.NET 4.5.2,實體框架6.1.3和System.Linq我遇到了一個令人困惑的異常。這個例外本身似乎並沒有包含有用的信息來確定它爲什麼會被提出。EF6 NullReferenceException與任何ToList()

下面的代碼線被執行時在一個NullReferenceException結果: dbCtx.Customers.ToList();

然而,以下行運行沒有異常和返回正確的結果: (dbCtx.Customers).ToList();

運行括號包圍表達第一將使兩種形式無一例外地執行:

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

我也想說明一下牛逼增加實體按預期工作:

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

Customer實體類:

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

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

BaseEntity類:

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

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

怎麼可能會導致這種行爲?

編輯: 當任何實體如.ToList(),.Count()等被調用時發生此問題。

異常詳細信息:

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 

編輯2:

實驗我已經將範圍縮小到一個呼叫dbCtx.Database.CompatibleWithModel(bool)後。所提供的論證是真是假都沒有區別。當我將它評論出來後,在代碼中稍後會引發NullReferenceException。我不知道爲什麼。調用dbCtx.Database.Exists()工作正常。 另外,dbCtx.Database.Initialize(false);也可靠地產生錯誤(不是在callsite上,而是在xyz.ToList()上)。

+1

哪裏了異常的堆棧跟蹤表明,它實際上是被拋出?它似乎相當棘手,無論如何,這可能是有趣的知道。此外,如果您不允許延遲加載,問題是否會持續存在? – jmcilhinney

+0

@jmcilhinney我已經更新了異常細節的問題。將延遲加載設置爲false仍然會得到相同的結果。 –

+2

也許這是因爲'客戶'被'密封',EF正試圖創建一個更改跟蹤代理,並且它失敗了?看到這個答案https://stackoverflow.com/a/5599270/235671 – t3chb0t

回答

0

我找到了一個解決方案。盡我所知,這是由於子女IDatabaseInitializer的方法範圍之外的某些方法如Database.Initialize()Database.CompatibleWithModel()被調用所致。也許這些方法涉及一些未知的副作用..?

我會包括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); 
    } 
} 
0

對於我所知道的兩個表達式(有和沒有括號)是絕對等價的,不可能導致不同的行爲。您可以通過查看生成的IL代碼來檢查它(以下是:A tool for easy IL code inspection)。在這種難懂的案例中,我通常會懷疑某種形式的多線程是罪魁禍首。嘗試隔離違規代碼到最低限度,並看看你是否仍然可以重現這一點。

+2

這是一個有用的評論,但它肯定不是問題的答案 –

+0

我已經更新了這個問題,以便在進一步的實驗/分離後反映新的發現。 –

+0

問題的一個部分是:如何在一個語句中添加括號可以使某些內容有效並且沒有方括號開始突破 - 答案是:這不可能,您的觀察錯誤,尋找不同的原因,像多線程。這不是太遙遠,恕我直言。 – dnickless