Entity Framework CodeFirst KeyNotFoundException in MemberDomainMap

entity-framework-4.3

Trying to run down an error in my EF datacontext implementation that is yielding a fairly cryptic error.

Test Name:  Nodes_can_be_saved
Test FullName:  MyProj.Test.Integration.AFDataContextTest.Nodes_can_be_saved
Test Source:    c:\Users\pvencill. \Documents\Visual Studio 2012\Projects\MyProj\MyProj.Test\Integration\AFDataContextTest.cs : line 49
Test Outcome:   Failed
Test Duration:  0:00:01.4192808

Result Message: 
Test method MyProj.Test.Integration.AFDataContextTest.Nodes_can_be_saved threw exception: 
System.Data.Entity.Infrastructure.DbUpdateException: Error retrieving values from ObjectStateEntry. See inner exception for details. ---> System.Data.UpdateException: Error retrieving values from ObjectStateEntry. See inner exception for details. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
Result StackTrace:  
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at System.Data.Mapping.ViewGeneration.Structures.MemberDomainMap.GetDomainInternal(MemberPath path)
   at System.Data.Mapping.ViewGeneration.QueryRewriting.FragmentQueryKB.CreateIsOfTypeCondition(MemberPath currentPath, IEnumerable`1 derivedTypes, MemberDomainMap domainMap)
   at System.Data.Mapping.ViewGeneration.QueryRewriting.FragmentQueryKB.CreateVariableConstraintsRecursion(EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
   at System.Data.Mapping.ViewGeneration.QueryRewriting.FragmentQueryKB.CreateVariableConstraintsRecursion(EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
   at System.Data.Mapping.ViewGeneration.ViewgenContext..ctor(ViewTarget viewTarget, EntitySetBase extent, IEnumerable`1 extentCells, CqlIdentifiers identifiers, ConfigViewGenerator config, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap, StorageEntityContainerMapping entityContainerMapping)
   at System.Data.Mapping.ViewGeneration.ViewGenerator.CreateViewgenContext(EntitySetBase extent, ViewTarget viewTarget, CqlIdentifiers identifiers)
   at System.Data.Mapping.ViewGeneration.ViewGenerator.GenerateDirectionalViewsForExtent(ViewTarget viewTarget, EntitySetBase extent, CqlIdentifiers identifiers, KeyToListMap`2 views)
   at System.Data.Mapping.ViewGeneration.ViewGenerator.GenerateDirectionalViews(ViewTarget viewTarget, CqlIdentifiers identifiers, KeyToListMap`2 views)
   at System.Data.Mapping.ViewGeneration.ViewGenerator.GenerateAllBidirectionalViews(KeyToListMap`2 views, CqlIdentifiers identifiers)
   at System.Data.Mapping.ViewGeneration.ViewgenGatekeeper.GenerateViewsFromCells(List`1 cells, ConfigViewGenerator config, CqlIdentifiers identifiers, StorageEntityContainerMapping containerMapping)
   at System.Data.Mapping.ViewGeneration.ViewgenGatekeeper.GenerateViewsFromMapping(StorageEntityContainerMapping containerMapping, ConfigViewGenerator config)
   at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.SerializedGenerateViews(StorageEntityContainerMapping entityContainerMap, Dictionary`2 resultDictionary)
   at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.SerializedGetGeneratedViews(EntityContainer container)
   at System.Data.Common.Utils.Memoizer`2.<>c__DisplayClass2.<Evaluate>b__0()
   at System.Data.Common.Utils.Memoizer`2.Result.GetValue()
   at System.Data.Common.Utils.Memoizer`2.Evaluate(TArg arg)
   at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection)
   at System.Data.Mapping.Update.Internal.ViewLoader.InitializeEntitySet(EntitySetBase entitySetBase, MetadataWorkspace workspace)
   at System.Data.Mapping.Update.Internal.ViewLoader.SyncInitializeEntitySet[TArg,TResult](EntitySetBase entitySetBase, MetadataWorkspace workspace, Func`2 evaluate, TArg arg)
   at System.Data.Mapping.Update.Internal.ViewLoader.SyncContains[T_Element](EntitySetBase entitySetBase, MetadataWorkspace workspace, Set`1 set, T_Element element)
   at System.Data.Mapping.Update.Internal.ExtractorMetadata..ctor(EntitySetBase entitySetBase, StructuralType type, UpdateTranslator translator)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.GetExtractorMetadata(EntitySetBase entitySetBase, StructuralType type)
   at System.Data.Mapping.Update.Internal.ExtractorMetadata.ExtractResultFromRecord(IEntityStateEntry stateEntry, Boolean isModified, IExtendedDataRecord record, Boolean useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
   at System.Data.Mapping.Update.Internal.RecordConverter.ConvertStateEntryToPropagatorResult(IEntityStateEntry stateEntry, Boolean useCurrentValues, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
 --- End of inner exception stack trace ---
    at System.Data.Mapping.Update.Internal.RecordConverter.ConvertStateEntryToPropagatorResult(IEntityStateEntry stateEntry, Boolean useCurrentValues, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
   at System.Data.Mapping.Update.Internal.ExtractedStateEntry..ctor(UpdateTranslator translator, IEntityStateEntry stateEntry)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.LoadStateEntry(IEntityStateEntry stateEntry)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.PullModifiedEntriesFromStateManager()
   at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
   at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
   at System.Data.Entity.Internal.InternalContext.SaveChanges()
 --- End of inner exception stack trace ---
    at System.Data.Entity.Internal.InternalContext.SaveChanges()
   at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
   at System.Data.Entity.DbContext.SaveChanges()
   at MyProj.Data.MyProjDataContext.SaveChanges() in c:\Users\pvencill. \Documents\Visual Studio 2012\Projects\MyProj\MyProj.Data\MyProjDataContext.cs:line 44
   at MyProj.Test.Integration.AFDataContextTest.Nodes_can_be_saved() in c:\Users\pvencill. \Documents\Visual Studio 2012\Projects\MyProj\MyProj.Test\Integration\AFDataContextTest.cs:line 55

Researching the error led to few hits on Google, but the ones I found suggested that it's something to do w/ my model relationships, though in looking at the DB that the migrations generated, all seems in order to my eyes. My relevant models are as follows:

My data context DBSets and modelCreating definition:

public DbSet<Blip> Blips { get; set; }
        public DbSet<SensorAdapter> Sensors { get; set; }
        public DbSet<NodeReport> NodeReports { get; set; }
        public DbSet<Node> Nodes { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Blip>().Property(b => b.TimeStamp).HasColumnType("datetime2");
            modelBuilder.Entity<Node>().HasMany<NodeReport>(n => n.NodeReports).WithRequired(nr=>nr.Node);
            modelBuilder.Entity<Blip>().HasMany<NodeReport>(b => b.NodeReports);

            base.OnModelCreating(modelBuilder);
        }

The Blips and SensorAdapter objects worked fine prior to adding NodeReports to them, so I suspect it's in there that the project lies.

I have a base Entity object that all my stuff inherits from, which just defines an Id property of type T; that was working fine.

NodeReport inherits from Report, whose definition is here:

public abstract class Report : Entity<long>
    {
        public Report()
        {
            Status = Status.Unknown;
        }

        public DateTime TimeStamp { get; set; }
        public Status Status { get; set; }
        public String Raw { get; set; }
    }

NodeReport in turn is defined thus:

public class NodeReport : Report
    {
        public virtual Node Node { get; set; }
        //public virtual Blip Blip { get; set; }
    }

I tried it both with and without the Blip on there, commented out at the moment as I try and narrow down the problem

A Node is a fairly sparse class at hte moment too:

public class Node : Entity<long>
    {
        public Node ()
        {
                       NodeReports = new List<NodeReport>();
        }

        public String HostName { get;set; }
        public String Description { get; set; }
            public virtual IList<NodeReport> NodeReports { get; set; }
    }

Any suggestions would be greatly appreciated, I've been beating myself up trying to figure it.

Best Solution

Well, after much searching through my code and rebuilding from scratch I found that the problem was actually that I had a derived class of Node that had a Uri as a property, which obviously failed mapping since it doesn't have a default constructor (and possibly other reasons). I solved it for now by simply changing the property to a String which I validate as a Uri internally, though I would have preferred a more elegant solution. I tried mapping Uri and even a custom subclass (w/ default constructor) of Uri to a complextype, but that didn't help.

Still, the question above is answered.

Related Question