Strange null reference exception in LINQ query with EF

c#, ef-code-first, entity-framework, linq

Solution

The only way that your code would throw an exception would be if pv.ContextParam were null, because that is the only place you are dereferencing something that might cause a null pointer exception.

This would happen if you have ContextParamValues records without a corresponding ContextParam record, thus ContextParam would be null. Since we can't see your data model, you will have to check for that.

Add this line of code and check in the debugger to see if it's true:

bool containsNulls = db.ContextParamValues
    .Include(x => x.ContextParam)
    .Any(x => x.ContextParam == null)

EDIT (removed all the middle steps, check history if you're interested):

Well, this doesn't actually answer the question, but it would solve your problem. Let's just rewrite your code to be simpler and more efficient. If I read your code right, all you're looking to do is return the ContextInstances that have associated ContextValueParams with the provided name/value pairs, correct?

Why not just do this (add includes as you see fit):

public List<ContextInstance> GetContextInstances(
       string[] ParamNames, string[] ParamValues, bool AsNoTracking = false)
{
    var p = ParamNames.Zip(ParamValues, (a,b) => a+b);

    var ctx = db.ContextInstances
       .Where(x => p.All(y => x.ContextParamValues
          .Select(z => z.ContextParam.Name + z.Value).Contains(y)));

    return (AsNoTracking ? ctx.AsNoTracking() : ctx).ToList();
}

Problem

I have the following three related entity classes: ``` public class ContextInstance { public Int64 Id { get; set; } public virtual List<ContextParamValue> ContextParamValues { get; set; } } public class ContextParamValue { public Int64 Id { get; set; } public virtual Int64 ContextParamId { get; set; } public virtual ContextParam ContextParam { get; set; } public virtual ContextInstance ContextInstance { get; set; } public virtual Int64 ContextInstanceId { get; set; } public string Value { get; set; } } public class ContextParam { public Int64 Id { get; set; } [Required] public string Name { get; set; } [DefaultValue("")] public string Description { get; set; } } ``` I have set up fluent relationships as follows: ``` modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); modelBuilder.Entity<ContextInstance>() .HasMany(ci => ci.ContextParamValues) .WithRequired(cpv => cpv.ContextInstance) .HasForeignKey(cpv => cpv.ContextInstanceId) .WillCascadeOnDelete(true); ``` I have the following "Helper" class, the ParamValueToList method of which is intermittently throwing a null-reference exception: ``` public class RuntimeHelper : IDisposable { DocumentDbContext db; ConfigurationHelper ch; private RuntimeHelper() { } public RuntimeHelper(DocumentDbContext context) { db = context; ch = new ConfigurationHelper(context); } public List<ContextParamValue> ParamValuesToList(string[] ParamNames, string[] ParamValues) { Trace.TraceInformation("-- ParamValuesToList invoked --"); if (ParamNames != null && ParamNames.Length != ParamValues.Length) throw new System.ArgumentException("ParamNames and ParamValues may not differ in length."); Dictionary<string, string> d = new Dictionary<string, string>(); for (int i = 0; i < ParamNames.Length; i++) { string pName = ParamNames[i]; string pValue = ParamValues[i]; d.Add(pName, pValue); Trace.TraceInformation("ParamValuesToList Key: " + pName + "; Value: " + pValue + ";"); } Trace.TraceInformation("Value of db:" + db.ContextParamValues.ToString()); var cpvList = db.ContextParamValues .Include(x => x.ContextParam) .ToArray<ContextParamValue>(); List<ContextParamValue> lst = cpvList .Where(pv => d.Contains(new KeyValuePair<string, string>(pv.ContextParam.Name, pv.Value))) //.Where(pv => true == true) .ToList<ContextParamValue>(); Trace.TraceInformation("-- ParamValuesToList executed --"); return lst; } public List<ContextInstance> GetContextInstances(List<ContextParamValue> ContextParamValues, bool AsNoTracking = false) { if (!AsNoTracking) return db.ContextInstances .Include(x => x.ContextClass) .Include(x => x.ContextParamValues.Select(p => p.ContextParam)) .Include(x => x.Documents) .AsEnumerable<ContextInstance>() // <-- Allows boolean method as part of LINQ query .Where(ci => IsSubset(ci.ContextParamValues, ContextParamValues)) .ToList<ContextInstance>(); else return db.ContextInstances .Include(x => x.ContextClass) .Include(x => x.ContextParamValues.Select(p => p.ContextParam)) .Include(x => x.Documents) .AsNoTracking() .AsEnumerable<ContextInstance>()// <-- Allows boolean method as part of LINQ query .Where(ci => IsSubset(ci.ContextParamValues, ContextParamValues)) .ToList<ContextInstance>(); } public List<ContextInstance> GetContextInstances(string[] ParamNames, string[] ParamValues, bool AsNoTracking = false) { return GetContextInstances(ParamValuesToList(ParamNames, ParamValues), AsNoTracking); } } ``` The specific statement from the above method that is throwing the error is ``` List<ContextParamValue> lst = cpvList .Where(pv => d.Contains(new KeyValuePair<string, string>(pv.ContextParam.Name, pv.Value))) .ToList<ContextParamValue>(); ``` The null reference exception is NOT thrown under the following condition: - There exist, for a given ContextInstance, only 1 ContextParamValue - Example, ContextParamValue.ContextParam.Name = "ClientId" and ContextParamValue1.Value = "1" The null reference exception is thrown under the following condition: - There exist, for a given ContextInstance, two-or-more ContextParamValues - Example, ContextParamValue1.ContextParam.Name = "ClientId" and ContextParamValue1.Value = "1" PLUS ContextParamValue2.ContextParam.Name = "MotivationId" and ContextParamValue2.Value = "1". I can confirm the following about the helper method in question: - d is not null nor does it contain any keyvaluepairs with null values - cpvList is not null and not empty when the error occurs. - ContextParam does not load for parent ContextParamValue entities in all cases (it only loads for the first ContextParamValue instance but for subsequent instances only a null value is loaded). - There are no null ContextParam entries in database... All ContextParamValues has one ContextParam entry. The following trace and stacktrace information is generated during runtime: Application: 2014-05-16T19:00:20 PID[4800] Error System.NullReferenceException: Object reference not set to an instance of an object. Application: at DocumentManagement.Helpers.RuntimeHelper.<>c__DisplayClass28.b__27(ContextParamValue pv) in c:\Users\xxx\Dropbox\xxx\Active Projects\xxx\DocumentManagement\Helpers\DocsHelper_RT.cs:line 229 Application: at System.Linq.Enumerable.WhereArrayIterator1.MoveNext() Application: at System.Collections.Generic.List1..ctor(IEnumerable1 collection) Application: at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) Application: at DocumentManagement.Helpers.RuntimeHelper.ParamValuesToList(String[] ParamNames, String[] ParamValues) in c:\Users\xxx\Dropbox\xxx\Active Projects\xxx\DocumentManagement\Helpers\DocsHelper_RT.cs:line 228 Application: at DocumentManagement.Helpers.RuntimeHelper.GetContextInstances(String[] ParamNames, String[] ParamValues, Boolean AsNoTracking) in c:\Users\xxx\Dropbox\xxx\Active Projects\xxx\DocumentManagement\Helpers\DocsHelper_RT.cs:line 262 Application: at xxx.Controllers.ClientController.LoadStep2(Int64 ClientId, String Error) in c:\Users\xxx\Dropbox\xxx\Active Projects\xxx\xxx\Views\Client\ClientController.cs:line 198

Original source