Very strange behaviour from EF which has me pulling my hair out.
The problem pertains mainly to the following entity class, and it's encapsulated properties:
public class ContextParamValue
{
public Int64 Id { get; set; }
public Int64 ContextParamId { get; set; }
public virtual ContextParam ContextParam { get; set; }
public virtual ContextInstance ContextInstance { get; set; }
public Int64 ContextInstanceId { get; set; }
public string Value { get; set; }
}
As you can see, I have a ContextParamValue class, which has a unidirectional 1 to 1 relationship with ContextParam. Thus, ContextParamValue can access ContextParam but not the other way around.
The piece of code that has me in tatters are as follows:
public List<ContextParamValue> ParamValuesToList(string[] ParamNames, string[] ParamValues)
{
if (ParamNames != null && ParamNames.Length != ParamValues.Length)
throw new System.ArgumentException("ParamNames and ParamValues may not differ in length.");
List<ContextParamValue> rList = new List<ContextParamValue>();
for (int i = 0; i < ParamNames.Length; i++)
{
string pName = ParamNames[i];
string pValue = ParamValues[i];
List<ContextParamValue> lst = db.ContextParamValues
//.Include(x => x.ContextParam)
.Where(pv => pv.ContextParam.Name.ToLower().Trim().Equals(pName.ToLower().Trim()))
.Where(pv => pv.Value.Equals(pValue))
.ToList<ContextParamValue>();
rList.AddRange(lst);
}
return rList;
}
The strange result of this code is that ContextParam
is only loaded for the first element returned in rList
. All the subsequent elements in rList
has a null value for the ContextParam
property. The following screenshots shows the element instance values during debugging:
First element in the collection... WINNING!
Second element in the collection... MASSIVE FAIL!
I have tried multiple alternative implementations for the above method, namely lazy loading, eager loading, even not building up the list from within a loop (I constructed a dictionary of the ParamNames
and ParamValues
array objects which allowed me to do set-based matching within the LINQ expression). Same result every time.
I also include the relevant snippets from my DbContext
class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
ModelMapper.InitializeRelationshipMappings(modelBuilder);
base.Configuration.LazyLoadingEnabled = true;
}
AND
public static class ModelMapper
{
public static void InitializeRelationshipMappings(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
modelBuilder.Entity<Document>()
.HasRequired(d => d.FileItem)
.WithOptional(fi => fi.Document)
.WillCascadeOnDelete(true);
modelBuilder.Entity<Document>()
.HasMany(d => d.DocumentClasses)
.WithMany(dc => dc.Documents);
modelBuilder.Entity<ContextClass>()
.HasMany(cc => cc.RequiredClasses);
modelBuilder.Entity<ContextClass>()
.HasMany(cc => cc.OptionalClasses);
modelBuilder.Entity<ContextClass>()
.HasMany(cc => cc.Params)
.WithRequired(cp => cp.ContextClass)
.WillCascadeOnDelete(true);
modelBuilder.Entity<ContextInstance>()
.HasRequired(ci => ci.ContextClass);
modelBuilder.Entity<ContextInstance>()
.HasMany(ci => ci.ContextParamValues)
.WithRequired(cpv => cpv.ContextInstance)
.HasForeignKey(cpv => cpv.ContextInstanceId)
.WillCascadeOnDelete(true);
modelBuilder.Entity<ContextParamValue>()
.HasRequired(cpv => cpv.ContextParam);
}
}
Else try replacing your code
List<ContextParamValue> lst = db.ContextParamValues //.Include(x => x.ContextParam) .Where(pv => pv.ContextParam.Name.ToLower().Trim().Equals(pName.ToLower().Trim())) .Where(pv => pv.Value.Equals(pValue)) .ToList<ContextParamValue>(); rList.AddRange(lst);
with another LINQ
List<ContextParamValue> lst = from db.ContextParamValues.Where(pv => pv.ContextParam.Name.ToLower() == pName.ToLower().Trim()
&& db.ContextParamValues.Where(pv => pv.Value == pValue)).ToList<ContextParamValue>();
Humour me, please. Put your whole for
loop inside a using
block:
using (var myDb = new MyDataContext())
{
for (int i = 0; i < ParamNames.Length; i++)
{
//etc., replacing "db" with "myDb"
}
}
I would be interested to know if this changes anything.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.