"The reference to the object is not installed in the instance of the object" - but nothing is empty?

Yes, you probably think; "God, another one?"

Yes, one more.

"The reference to the object is not installed in the instance of the object."

I have been working with EF6 recently and after development for some time, I found that a little more optimization is required. Alot was recycled without problems, but it seems I can not understand this one.

In my application, I used this piece of pseudocode to retrieve items from a database.

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

Note that DbContext exists for clarification only. It becomes available when necessary.

This approach β€œworks,” but that would mean that if I had, say, 20 names to search for, I would be in the database about 20 times. Oh!

So I started looking for a way to implement one request. I found a way, but it does not work as it should. This is my current approach;

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

This should, as far as I know, translate into SELECT ... FROM Names WHERE ... IN (...) . However, my application crashes with foreach(var name in query) as soon as it reaches name , throwing a dangerous NullReferenceException . However, it passes if(query == null) , i.e. the query is not null. At that moment, I was confused. How can it be not empty, but still throw this error?

I was not sure if the request is being executed if I try to access it with this approach. So I tried to create a list from the query using ToList() , but when creating the list, this throws the same exception.

It seems that every time I call query , it gives me a NullReferenceException . However, it still passes if(query == null) . So my question is:

Why does this pass the test, but is it not available? I misunderstood IQueryable<> ? And if I misunderstood, how to do it right?

EDIT

I have debugging before posting. I know that for sure;

  • names not null.
  • context not null.

Code calling the function:

 //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 } //... } 

EDIT 2

After some additional debugging, I found that the generated query is slightly different. It is assumed that

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

However, I get this:

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

As the actual request.

Stack trace

 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 
+7
c # dbcontext entity-framework-6
source share
3 answers

After you published stacktrace, I noticed that you are using MySQL, so I assume you got this error: Exception when using IEnumera.Contains (model.property) in Where is the predicate

Thus, the solution would be to ensure that you have versions of MySQL Connector / NET 6.7.6 / 6.8.4 / 6.9.5 and later. Or try using the Any method instead of Contains .

Ps This error report came from this publication from Alnedru: Int []. Contains not working in EF6

+2
source share

Your zero query check will never fail because it returns an IQueryable object (i.e. a constructed query). You created it and started building the request, so it will always go through.

To be clear - IQueryable is roughly equivalent to a string containing the ADO.Net Select statement. This is not essentially factual evidence.

This does not explain why it throws an empty exception, but explains why it skips the zero check, and foreach can still fail.

EDIT: When trying to duplicate this, I found that I was getting an exception when using the code below:

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

It was not a NullReferenceException , but a NotSupportedException , since ICollections Contains does not support SQL translation. When switching the parameter to List problem disappeared:

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

Or you can convert it to a list on the fly:

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

Why don't you just add an extension method to ease the stress it brings to you. try this piece of code

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

and then call it that

 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; } } 
-2
source share

All Articles