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