public override IEdmModel GetEdmModel() { if (_isModelBeingBuilt) { throw Error.NotSupported(SRResources.GetEdmModelCalledMoreThanOnce); } // before we begin, get the set of types the user had added explicitly. _explicitlyAddedTypes = new List <IStructuralTypeConfiguration>(StructuralTypes); _isModelBeingBuilt = true; MapTypes(); _conventionsBeingApplied = true; // Apply type conventions. Note the call to ToArray() is required as the StructuralTypes collection // could get modified during ApplyTypeConventions(). foreach (IStructuralTypeConfiguration edmTypeConfiguration in StructuralTypes.ToArray()) { ApplyTypeConventions(edmTypeConfiguration); } // Apply property conventions. Note the call to ToArray() is required as the StructuralTypes collection // could get modified during ApplyPropertyConventions(). Also, type conventions might have // modified this. So, call ToArray() again. foreach (IStructuralTypeConfiguration edmTypeConfiguration in StructuralTypes.ToArray()) { ApplyPropertyConventions(edmTypeConfiguration); } // Don't RediscoverComplexTypes() and treat everything as an entity type if buidling a model for QueryableAttribute. if (!_isQueryCompositionMode) { RediscoverComplexTypes(); } // prune unreachable types PruneUnreachableTypes(); // Apply entity set conventions. IEnumerable <IEntitySetConfiguration> explictlyConfiguredEntitySets = new List <IEntitySetConfiguration>(EntitySets); foreach (IEntitySetConfiguration entitySet in explictlyConfiguredEntitySets) { ApplyEntitySetConventions(entitySet); } return(base.GetEdmModel()); }
// the convention model builder MapTypes() method might have went through deep object graphs and added a bunch of types // only to realise after applying the conventions that the user has ignored some of the properties. So, prune the unreachable stuff. private void PruneUnreachableTypes() { Contract.Assert(_explicitlyAddedTypes != null); // Do a BFS starting with the types the user has explicitly added to find out the unreachable nodes. Queue <IStructuralTypeConfiguration> reachableTypes = new Queue <IStructuralTypeConfiguration>(_explicitlyAddedTypes); HashSet <IStructuralTypeConfiguration> visitedTypes = new HashSet <IStructuralTypeConfiguration>(); while (reachableTypes.Count != 0) { IStructuralTypeConfiguration currentType = reachableTypes.Dequeue(); // go visit other end of each of this node's edges. foreach (PropertyConfiguration property in currentType.Properties.Where(property => property.Kind != PropertyKind.Primitive)) { if (property.Kind == PropertyKind.Collection) { // if the elementType is primitive we don't need to do anything. CollectionPropertyConfiguration colProperty = property as CollectionPropertyConfiguration; if (EdmLibHelpers.GetEdmPrimitiveTypeOrNull(colProperty.ElementType) != null) { continue; } } IStructuralTypeConfiguration propertyType = GetStructuralTypeOrNull(property.RelatedClrType); Contract.Assert(propertyType != null, "we should already have seen this type"); if (!visitedTypes.Contains(propertyType)) { reachableTypes.Enqueue(propertyType); } } visitedTypes.Add(currentType); } IStructuralTypeConfiguration[] allConfiguredTypes = StructuralTypes.ToArray(); foreach (IStructuralTypeConfiguration type in allConfiguredTypes) { if (!visitedTypes.Contains(type)) { // we don't have to fix up any properties because this type is unreachable and cannot be a property of any reachable type. RemoveStructuralType(type.ClrType); } } }