繁体   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