LINQ exception exception with EF

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 established a loose relationship 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 periodically throws an exception using a NULL reference:

 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 operator from the above method, which throws an error,

 List<ContextParamValue> lst = cpvList .Where(pv => d.Contains(new KeyValuePair<string, string>(pv.ContextParam.Name, pv.Value))) .ToList<ContextParamValue>(); 

A null reference exception is NOT thrown under the following condition:

  • Only 1 ContextParamValue exists for this ContextInstance
  • Example: ContextParamValue.ContextParam.Name = "ClientId" and ContextParamValue1.Value = "1"

The null reference exception refers to the following condition:

  • For this ContextInstance, there are 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 and does not contain any keys with null values
  • cpvList is not null and is not empty when an error occurs.
  • ContextParam does not load ContextParamValue for parent objects in all cases (it is loaded only for the first instance of ContextParamValue, but only zero value is loaded for subsequent instances).
  • There are no null ContextParam entries in the database ... All ContextParamValues โ€‹โ€‹have one ContextParam entry.

During execution, the following trace and stack information is generated:

Application: 2014-05-16T19: 00: 20 PID [4800] Error System.NullReferenceException: the reference to the object is not installed in the object instance. Usage: with 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: in System.Linq.Enumerable.WhereArrayIterator1.MoveNext () : in System.Collections.Generic.List1..ctor (IEnumerable1 collection) Application: with System.Linq.Enumerable.ToList [TSource] (source IEnumerable1) Application: with 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: with 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 Appendix: in xx x.Controllers.ClientController.LoadStep2 (Int64 ClientId, String Error) in c: \ Users \ xxx \ Dropbox \ xxx \ Active Projects \ xxx \ xxx \ Views \ Client \ ClientController.cs: line 198

enter image description here

enter image description here

+6
source share
1 answer

The only way your code will throw an exception will be if pv.ContextParam was null, as this is the only place you are looking for something that could lead to a null pointer exception.

This will happen if you have ContextParamValues โ€‹โ€‹without the corresponding ContextParam, so ContextParam will be null. Since we cannot see your data model, you will need to verify this.

Add this line of code and check the debugger to make sure it is true:

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

EDIT (remove all middle steps, check history if you are interested):

Well, this does not really answer the question, but it will solve your problem. Let us simply rewrite your code to be simpler and more efficient. If I read your code correctly, all you have to do is return ContextInstances that are related to ContextValueParams with the provided name / value pairs, right?

Why not just do it (the addition includes, at your discretion):

 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(); } 
+5
source

Source: https://habr.com/ru/post/969399/


All Articles