簡體   English   中英

“對象引用未設置為對象的實例”-但是沒有什么是空的?

[英]“Object reference not set to an instance of an object” - but nothing is null?

是的,您可能會認為; “上帝,另一個?”。

是的,另一個。

“你調用的對象是空的。”

我最近一直在使用EF6,經過一段時間的開發,我發現還需要更多的優化。 很多已經過重做,沒有任何問題,但看來我無法弄清楚。

在我的應用程序中,我一直在使用這段偽代碼從數據庫中獲取項目。

DbContext context = new DbContext();

public IEnumerable<string> GetExistingNames(IEnumerable<string> names)
{
    foreach(string name in names)
    {
        string existingName = context.Names.Where(n => n.Name == name).FirstOrDefault();
        if(existingName == null) continue;
        yield return existingName;
    }
}

請注意, DbContext僅在此處進行說明。 在需要時將其丟棄。

這種方法“有效”,但是這意味着如果我要查找20個名字,那么我將訪問數據庫約20次。 哎喲!

因此,我開始尋找一種實現單個查詢的方法。 我已經找到了一種方法,但實際上並沒有按預期方式工作。 這是我目前的做法;

public IEnumerable<string> GetExistingNames(ICollection<string> names)
{
    IQueryable<Names> query = context.Names.Where(n => names.Contains(n.Name));
    if(query == null) yield break;
    foreach(var name in query)
    {
        yield return name.Name;
    }
}

據我所知,這應該翻譯成SELECT ... FROM Names WHERE ... IN (...) 但是,我的應用程序一旦擊中name ,就會在foreach(var name in query)中的foreach(var name in query)處崩潰,並拋出令人恐懼的NullReferenceException 但是,它確實傳遞了if(query == null) ,這意味着查詢不為null。 在這一點上,我感到困惑。 如何不能不為null,但仍然會拋出此錯誤?

如果我嘗試使用這種方法訪問查詢,我不確定查詢是否得到執行。 因此,我嘗試使用ToList()從查詢創建列表,但這在創建列表時引發了相同的異常。

似乎每次我調用query ,它都會給我NullReferenceException 但是,它仍然通過if(query == null) 所以,我的問題是;

它為什么通過測試,但是無法訪問? 我是否誤解了IQueryable<> 如果我誤解了它,應該如何正確進行處理?

編輯

發布前我已調試。 我肯定知道;

  • names不為null。
  • context不為null。

代碼調用函數:

//A wrapper for the DbContext. This is only used for some methods
//which require the DbContext
DbContextWrapper wrapper = new DbContextWrapper();

public void ProcessNames(List<string> inputNames)
{
    //...

    foreach(string existingName in wrapper.GetExistingNames(inputNames))
    {
        //Do something with the names
    }

    //...
}

編輯2

經過更多調試后,我發現所創建的查詢有些不同。 應該是;

SELECT `Extent1`.`Name` 
FROM `Names` AS `Extent1` 
WHERE (`Extent1`.`Name` IN ( @gp1,@gp2))

但是,我明白了。

System.Data.Entity.Infrastructure.DbQuery<MyDbContext.Names>

作為實際查詢。

堆棧跟蹤;

at MySql.Data.Entity.SqlGenerator.Visit(DbPropertyExpression expression)
at MySql.Data.Entity.SqlGenerator.Visit(DbInExpression expression)
at System.Data.Entity.Core.Common.CommandTrees.DbInExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
at MySql.Data.Entity.SqlGenerator.VisitBinaryExpression(DbExpression left, DbExpression right, String op)
at MySql.Data.Entity.SqlGenerator.Visit(DbAndExpression expression)
at System.Data.Entity.Core.Common.CommandTrees.DbAndExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
at MySql.Data.Entity.SelectGenerator.Visit(DbFilterExpression expression)
at System.Data.Entity.Core.Common.CommandTrees.DbFilterExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
at MySql.Data.Entity.SqlGenerator.VisitInputExpression(DbExpression e, String name, TypeUsage type)
at MySql.Data.Entity.SelectGenerator.VisitInputExpressionEnsureSelect(DbExpression e, String name, TypeUsage type)
at MySql.Data.Entity.SelectGenerator.Visit(DbProjectExpression expression)
at System.Data.Entity.Core.Common.CommandTrees.DbProjectExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
at MySql.Data.Entity.SelectGenerator.GenerateSQL(DbCommandTree tree)
at MySql.Data.MySqlClient.MySqlProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree)
at System.Data.Entity.Core.Common.DbProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree, DbInterceptionContext interceptionContext)
at System.Data.Entity.Core.Common.DbProviderServices.CreateCommandDefinition(DbCommandTree commandTree, DbInterceptionContext interceptionContext)
at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree, DbInterceptionContext interceptionContext, IDbDependencyResolver resolver, BridgeDataReaderFactory bridgeDataReaderFactory, ColumnMapFactory columnMapFactory)
at System.Data.Entity.Core.EntityClient.Internal.EntityProviderServices.CreateCommandDefinition(DbProviderFactory storeProviderFactory, DbCommandTree commandTree, DbInterceptionContext interceptionContext, IDbDependencyResolver resolver)
at System.Data.Entity.Core.EntityClient.Internal.EntityProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree, DbInterceptionContext interceptionContext)
at System.Data.Entity.Core.Common.DbProviderServices.CreateCommandDefinition(DbCommandTree commandTree, DbInterceptionContext interceptionContext)
at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.CreateCommandDefinition(ObjectContext context, DbQueryCommandTree tree)
at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.Prepare(ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, Boolean streaming, Span span, IEnumerable`1 compiledQueryParameters, AliasGenerator aliasGenerator)
at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at MyNameSpace.DbContextWrapper.<GetExistingNames>d__1b.MoveNext() in c:~omitted~\DbContextWrapper.cs:line 70
at MyNameSpace.NameProcessor.ProcessNames(List<string> inputNames) in c:~omitted~\NameProcessor.cs:line 60

發布stacktrace后,我發現您使用MySQL,因此我猜是您遇到了以下錯誤: 在Where謂詞中使用IEnumera.Contains(model.property)時發生異常

因此,解決方案是確保您具有MySQL Connector / NET 6.7.6 / 6.8.4 / 6.9.5和更高版本。 或者嘗試使用Any方法而不是Contains

Ps該錯誤報告來自Alnedru的帖子: Int []。包含在 EF6中不起作用

您對查詢的空檢查將永遠不會失敗,因為它返回的是IQueryable對象(即正在構建的查詢)。 您已實例化它並開始構建查詢,因此它將始終通過。

要清楚-IQueryable大致等效於包含ADO.Net Select語句的字符串。 本質上,它不是實際數據。

這並不能解釋為什么它拋出一個空例外,但解釋了為什么空檢查通過,並在foreach也不能正常工作。

編輯:嘗試重復此操作時,我發現使用以下代碼時出現異常:

public IEnumerable<string> GetExistingNames(ICollection<string> names)
{
    IQueryable<Names> query = Names.Where(n => names.Contains(n.Name));
    if (query == null) yield break;
    foreach (var name in query)
    {
        yield return name.Name;
    }
}

它不是NullReferenceException ,而是NotSupportedException ,因為ICollections Contains不支持對SQL的轉換。 將參數切換為List導致問題消失:

public IEnumerable<string> GetExistingNames(List<string> names)

或者,您可以將其即時轉換為列表:

IQueryable<Names> query = Names.Where(n => names.ToList().Contains(n.Name));

您為什么不只添加擴展方法來減輕由此帶來的壓力。 試試這段代碼

namespace HelperExtensionMethods
{
    public static class ExtensionMethods
    {
        public static string UpdateNullString(this string testNullstring)
        {
            if (TestNullstring == null)
                return "";
            return Testullstring;
        }
    }
}

然后這樣稱呼它

using HelperExtesionMethods
DbContext context = new DbContext();

public IEnumerable<string> GetExistingNames(ICollection<string> names)
{
    IQueryable<Names> query = context.Names.Where(n => names.UpdateNullString().Contains(n.Name.UpdateNullString()));
    if(query == null) yield break;
    foreach(var name in query)
    {
        yield return name.Name;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM