private IEnumerable <IEdmOperation> FindOperations(IEdmEntityType entityType, bool collection)
        {
            string fullTypeName = collection ? "Collection(" + entityType.FullName() + ")" :
                                  entityType.FullName();

            foreach (var item in _boundOperations)
            {
                if (item.Key.FullName() == fullTypeName)
                {
                    yield return(item.Value);
                }
            }
        }
예제 #2
0
        public void CreateComplexTypeWith_OneToMany_NavigationProperty()
        {
            // Arrange
            ODataModelBuilder builder = new ODataModelBuilder();

            builder.EntityType <Order>().HasKey(o => o.OrderId);

            ComplexTypeConfiguration <Customer> customer = builder.ComplexType <Customer>();

            customer.HasMany(c => c.Orders);

            // Act
            IEdmModel model = builder.GetEdmModel();

            // Assert
            IEdmEntityType orderType = Assert.Single(model.SchemaElements.OfType <IEdmEntityType>());

            Assert.Equal("Microsoft.AspNet.OData.Test.Builder.TestModels.Order", orderType.FullName());
            Assert.Equal("OrderId", orderType.DeclaredKey.Single().Name);
            Assert.Single(orderType.DeclaredProperties);
            Assert.Empty(orderType.NavigationProperties());

            IEdmComplexType customerType = Assert.Single(model.SchemaElements.OfType <IEdmComplexType>());

            Assert.Equal("Microsoft.AspNet.OData.Test.Builder.TestModels.Customer", customerType.FullName());

            IEdmNavigationProperty navProperty = Assert.Single(customerType.NavigationProperties());

            Assert.Equal(EdmMultiplicity.Many, navProperty.TargetMultiplicity());
            Assert.Equal("Orders", navProperty.Name);
            Assert.True(navProperty.Type.IsCollection());
            Assert.Same(orderType, navProperty.Type.AsCollection().ElementType().Definition);
        }
        internal static bool ShouldSuppressTypeNameSerialization(ODataEntry entry, IEdmEntityType edmType,
                                                                 ODataMetadataLevel metadataLevel)
        {
            Contract.Assert(entry != null);

            Contract.Assert(metadataLevel != ODataMetadataLevel.Default);

            switch (metadataLevel)
            {
            case ODataMetadataLevel.NoMetadata:
                return(true);

            case ODataMetadataLevel.FullMetadata:
                return(false);

            case ODataMetadataLevel.MinimalMetadata:
            default:     // All values already specified; just keeping the compiler happy.
                string pathTypeName = null;
                if (edmType != null)
                {
                    pathTypeName = edmType.FullName();
                }
                string entryTypeName = entry.TypeName;
                return(String.Equals(entryTypeName, pathTypeName, StringComparison.Ordinal));
            }
        }
예제 #4
0
        // OData formatter requires the type name of the entity that is being written if the type has derived types.
        // Expression
        //      source is GrandChild ? "GrandChild" : ( source is Child ? "Child" : "Root" )
        // Notice that the order is important here. The most derived type must be the first to check.
        // If entity framework had a way to figure out the type name without selecting the whole object, we don't have to do this magic.
        internal static Expression CreateTypeNameExpression(Expression source, IEdmEntityType elementType, IEdmModel model)
        {
            IReadOnlyList <IEdmEntityType> derivedTypes = GetAllDerivedTypes(elementType, model);

            if (derivedTypes.Count == 0)
            {
                // no inheritance.
                return(null);
            }
            else
            {
                Expression expression = Expression.Constant(elementType.FullName());
                for (int i = 0; i < derivedTypes.Count; i++)
                {
                    Type clrType = EdmLibHelpers.GetClrType(derivedTypes[i], model);
                    if (clrType == null)
                    {
                        throw new ODataException(Error.Format(SRResources.MappingDoesNotContainEntityType, derivedTypes[0].FullName()));
                    }

                    expression = Expression.Condition(
                        test: Expression.TypeIs(source, clrType),
                        ifTrue: Expression.Constant(derivedTypes[i].FullName()),
                        ifFalse: expression);
                }

                return(expression);
            }
        }
예제 #5
0
        public void CreateComplexTypeWith_OneToOneOrZero_NavigationProperty()
        {
            // Arrange
            ODataModelBuilder builder = new ODataModelBuilder();

            builder.EntityType <Customer>().HasKey(c => c.CustomerId);

            ComplexTypeConfiguration <Order> order = builder.ComplexType <Order>();

            order.HasOptional(o => o.Customer);

            // Act
            IEdmModel model = builder.GetEdmModel();

            // Assert
            IEdmEntityType customerType = Assert.Single(model.SchemaElements.OfType <IEdmEntityType>());

            Assert.Equal("System.Web.OData.Builder.TestModels.Customer", customerType.FullName());
            Assert.Equal("CustomerId", customerType.DeclaredKey.Single().Name);
            Assert.Equal(1, customerType.DeclaredProperties.Count());
            Assert.Empty(customerType.NavigationProperties());

            IEdmComplexType orderType = Assert.Single(model.SchemaElements.OfType <IEdmComplexType>());

            Assert.Equal("System.Web.OData.Builder.TestModels.Order", orderType.FullName());

            IEdmNavigationProperty navProperty = Assert.Single(orderType.NavigationProperties());

            Assert.Equal(EdmMultiplicity.ZeroOrOne, navProperty.TargetMultiplicity());
            Assert.Equal("Customer", navProperty.Name);
            Assert.True(navProperty.Type.IsEntity());
            Assert.Same(customerType, navProperty.Type.Definition);
        }
예제 #6
0
        /// <summary>
        /// Compares the properties (key, structural, navigation) of an EntityType element to those in the Edm model.
        /// </summary>
        /// <param name="typeElement">The EntityType element to compare to the model.</param>
        /// <param name="entityType">The corresponding EdmEntityType from the model.</param>
        /// <param name="typeIndex">All entity types from the model, indexed by qualified name.</param>
        private static void CompareEntityTypeProperties(XElement typeElement, IEdmEntityType entityType, IDictionary <string, XElement> typeIndex)
        {
            string fullTypeName = entityType.FullName();

            CompareBaseType(typeElement, entityType);

            Func <XElement, IEnumerable <string> > getKeyPropertyNames =
                (element) =>
            {
                var keyElement = element.EdmElements("Key").SingleOrDefault();
                return(keyElement == null?Enumerable.Empty <string>() : keyElement.EdmElements("PropertyRef").Select(e => e.GetAttributeValue("Name")));
            };

            // Collect all key properties from the type hierachy and compare
            var keyPropertyNames = RecurseBaseTypes(typeElement, typeIndex, getKeyPropertyNames).ToArray();

            var keyPropertiesOnModel = entityType.Key();

            ExceptionUtilities.Assert(keyPropertyNames.Count() == keyPropertiesOnModel.Count(), "Unexpected number of key properties on type " + fullTypeName);

            var missingKeyProperties = keyPropertyNames.Except(keyPropertiesOnModel.Select(p => p.Name)).ToArray();

            ExceptionUtilities.Assert(!missingKeyProperties.Any(), "Failed to find the key properties " + string.Join(",", missingKeyProperties) + " on type " + fullTypeName);

            // Collect all structural properties from the type hierachy and compare
            var propertyElements = RecurseBaseTypes(typeElement, typeIndex, (e) => e.EdmElements("Property"));

            CompareStructuralProperties(propertyElements, entityType);

            // Collect all navigation properties from the type hierachy and compare
            var navigationPropertyElements = RecurseBaseTypes(typeElement, typeIndex, (e) => e.EdmElements("NavigationProperty"));

            CompareNavigationProperties(navigationPropertyElements, entityType);
        }
예제 #7
0
        private string GetIdentifierPrefix(IEdmEntityType entityType)
        {
            if (entityType.BaseEntityType() != null)
            {
                return(GetIdentifierPrefix(entityType.BaseEntityType()));
            }
            TypeMapping existingMapping;

            if (_typeUriMap.TryGetValue(entityType.FullName(), out existingMapping))
            {
                return(existingMapping.IdentifierPrefix);
            }
            var keyList = entityType.DeclaredKey.ToList();

            if (keyList.Count != 1)
            {
                // Ignore this entity
                // TODO: Log an error
                return(null);
            }
            var identifierPrefix = GetStringAnnotationValue(keyList.First(), AnnotationsNamespace, "IdentifierPrefix");

            if (identifierPrefix == null)
            {
                // TODO: Log an error
            }
            return(identifierPrefix);
        }
        /// <summary>
        /// Get key value pair array for specifc odata resource using specifc entity type
        /// </summary>
        /// <param name="resource">The resource instance.</param>
        /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param>
        /// <param name="actualEntityType">The edm entity type of the resource</param>
        /// <returns>Key value pair array</returns>
        internal static KeyValuePair <string, object>[] GetKeyProperties(
            ODataResource resource,
            ODataResourceSerializationInfo serializationInfo,
            IEdmEntityType actualEntityType)
        {
            KeyValuePair <string, object>[] keyProperties = null;
            string actualEntityTypeName = null;

            if (serializationInfo != null)
            {
                if (String.IsNullOrEmpty(resource.TypeName))
                {
                    throw new ODataException(Strings.ODataResourceTypeContext_ODataResourceTypeNameMissing);
                }

                actualEntityTypeName = resource.TypeName;
                keyProperties        = ODataResourceMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(resource, ODataPropertyKind.Key, actualEntityTypeName);
            }
            else
            {
                actualEntityTypeName = actualEntityType.FullName();

                IEnumerable <IEdmStructuralProperty> edmKeyProperties = actualEntityType.Key();
                if (edmKeyProperties != null)
                {
                    keyProperties = edmKeyProperties.Select(p => new KeyValuePair <string, object>(p.Name, GetPrimitiveOrEnumPropertyValue(resource, p.Name, actualEntityTypeName, /*isKeyProperty*/ false))).ToArray();
                }
            }

            ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName);
            return(keyProperties);
        }
예제 #9
0
        internal static string GetJsonPayload(IEdmEntityType entityType, object value)
        {
            Type          valueType = value.GetType();
            StringBuilder sb        = new StringBuilder();

            sb.Append("{");
            sb.Append(Environment.NewLine);
            sb.Append("\t");
            sb.Append("@odata.type: \"" + entityType.FullName() + "\",");
            var properties = entityType.StructuralProperties().ToList();

            for (int i = 0; i < properties.Count; i++)
            {
                sb.Append("\t");
                IEdmProperty property = properties[i];
                // Type propertyType = ((PrimitiveType)property.TypeUsage.EdmType).ClrEquivalentType;
                PropertyInfo propertyInfo = valueType.GetProperty(property.Name);
                Type         propertyType = propertyInfo.PropertyType;
                propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
                object propertyValue = propertyInfo.GetValue(value, null);
                sb.Append(String.Format("{0}:{1}", properties[i].Name, PrimitiveToString(propertyValue, propertyType)));
                if (i != properties.Count - 1)
                {
                    sb.Append(",");
                }
                sb.Append(Environment.NewLine);
            }
            sb.Append("}");

            return(sb.ToString());
        }
예제 #10
0
        /// <summary>
        /// Get key value pair array for specific odata resource using specific entity type
        /// </summary>
        /// <param name="resource">The resource instance.</param>
        /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param>
        /// <param name="actualEntityType">The edm entity type of the resource</param>
        /// <param name="requiresId">Whether key properties are required to be returned</param>
        /// <returns>Key value pair array</returns>
        internal static KeyValuePair <string, object>[] GetKeyProperties(
            ODataResourceBase resource,
            ODataResourceSerializationInfo serializationInfo,
            IEdmEntityType actualEntityType,
            bool requiresId)
        {
            Debug.Assert(resource != null, "GetKeyProperties called for a null resource.");

            KeyValuePair <string, object>[] keyProperties = null;
            string actualEntityTypeName = string.IsNullOrEmpty(resource.TypeName) ? actualEntityType?.FullName() : resource.TypeName;

            // if we have serializationInfo, try that first
            if (serializationInfo != null)
            {
                keyProperties = ODataResourceMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(resource, ODataPropertyKind.Key, actualEntityTypeName);
            }

            // if we didn't get any keys from serializationInfo, try using entity type
            if ((keyProperties == null || keyProperties.Length == 0) && actualEntityType != null)
            {
                keyProperties = GetPropertyValues(actualEntityType.Key(), resource, actualEntityType, requiresId).ToArray();
            }

            if (!ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName, requiresId))
            {
                return(Enumerable.Empty <KeyValuePair <string, object> >().ToArray());
            }

            return(keyProperties);
        }
        private static void AppendTypeCastIfNeeded(StringBuilder builder, IEdmEntitySet entitySet, IEdmType expectedType)
        {
            ExceptionUtilities.CheckArgumentNotNull(builder, "builder");
            ExceptionUtilities.CheckArgumentNotNull(entitySet, "entitySet");

            IEdmEntityType entityDataType = expectedType as IEdmEntityType;

            if (entityDataType == null)
            {
                return;
            }


            if (entitySet.EntityType() == entityDataType)
            {
                // same types; nothing to add to the context URI
                return;
            }

            if (entityDataType.InheritsFrom(entitySet.EntityType()))
            {
                // derived type; add the type cast segment
                builder.Append("/");
                builder.Append(entityDataType.FullName());
                return;
            }

            ExceptionUtilities.Assert(false, "Expected entity type has to be compatible with the base entity type of the set.");
        }
예제 #12
0
        /// <summary>
        /// Find the Edm operation bounding to the given entity type.
        /// </summary>
        /// <param name="entityType">The binding entity type.</param>
        /// <param name="collection">The collection or not.</param>
        /// <returns>The found Edm operations.</returns>
        public IEnumerable <IEdmOperation> FindOperations(IEdmEntityType entityType, bool collection)
        {
            Utils.CheckArgumentNull(entityType, nameof(entityType));

            string fullTypeName = collection ? "Collection(" + entityType.FullName() + ")" : entityType.FullName();

            IList <IEdmOperation> edmOperations;

            _boundEdmOperations.Value.TryGetValue(fullTypeName, out edmOperations);

            foreach (IEdmEntityType derived in Model.FindAllDerivedTypes(entityType).OfType <IEdmEntityType>())
            {
                string subFullTypeName = collection ? "Collection(" + derived.FullName() + ")" : derived.FullName();

                if (_boundEdmOperations.Value.TryGetValue(subFullTypeName, out IList <IEdmOperation> edmSubOperations))
                {
                    foreach (var edmOperation in edmSubOperations)
                    {
                        edmOperations.Add(edmOperation);
                    }
                }
            }

            return(edmOperations);
        }
예제 #13
0
 private bool HasUnsatisfiedDerivedTypeConstraint(
     IEdmVocabularyAnnotatable annotatable,
     IEdmEntityType baseType,
     OpenApiConvertSettings convertSettings)
 {
     return(convertSettings.RequireDerivedTypesConstraintForBoundOperations &&
            !(_model.GetCollection(annotatable, "Org.OData.Validation.V1.DerivedTypeConstraint") ?? Enumerable.Empty <string>())
            .Any(c => c.Equals(baseType.FullName(), StringComparison.OrdinalIgnoreCase)));
 }
예제 #14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CastPathSegment" /> class.
        /// </summary>
        /// <param name="castType">The type of the cast.</param>
        public CastPathSegment(IEdmEntityType castType)
        {
            if (castType == null)
            {
                throw Error.ArgumentNull("castType");
            }

            CastType     = castType;
            CastTypeName = castType.FullName();
        }
예제 #15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CastPathSegment" /> class.
        /// </summary>
        /// <param name="castType">The type of the cast.</param>
        public CastPathSegment(IEdmEntityType castType)
        {
            if (castType == null)
            {
                throw Error.ArgumentNull("castType");
            }

            CastType = castType;
            CastTypeName = castType.FullName();
        }
예제 #16
0
        private string GetEntityTypeName(string tableName)
        {
            IEdmEntityContainer defaultContainer = GetDefaultEntityContainer(this.metadata);

            IEdmEntitySet entitySet = defaultContainer.FindEntitySet(tableName);

            IEdmEntityType entityType = entitySet.ElementType;

            return(entityType.FullName());
        }
예제 #17
0
        private bool TryGetEntityTypeWrapperForFixedEntityType(IEdmEntityType fixedEntityType, out EdmEntityTypeWrapper entityTypeWrapper)
        {
            if (fixedEntityType != null)
            {
                return(_entityTypes.TryGetValue(fixedEntityType.FullName(), out entityTypeWrapper));
            }

            entityTypeWrapper = null;
            return(false);
        }
예제 #18
0
        public void ParserTestDuplicateEntityTypes()
        {
            var csdls = ODataTestModelBuilder.InvalidCsdl.DuplicateEntityTypes;
            var model = this.GetParserResult(csdls);

            IEdmEntityContainer entityContainer = model.EntityContainer;

            Assert.AreEqual("DefaultContainer", entityContainer.Name, "Invalid entity container name");
            Assert.IsTrue(entityContainer.Elements.Count() == 2, "Entity container has invalid amount of elements");
            Assert.AreEqual(EdmContainerElementKind.EntitySet, entityContainer.Elements.ElementAt(0).ContainerElementKind, "Invalid container element kind");
            Assert.AreEqual(EdmContainerElementKind.EntitySet, entityContainer.Elements.ElementAt(1).ContainerElementKind, "Invalid container element kind");

            IEdmEntitySet entitySetElement1 = (IEdmEntitySet)entityContainer.Elements.ElementAt(0);

            Assert.AreEqual("DuplicateEntityType", entitySetElement1.Name, "Invalid entity set name");
            Assert.AreEqual("TestModel.DuplicateEntityType", entitySetElement1.EntityType().FullName(), "Invalid entity set element type");

            IEdmEntitySet entitySetElement2 = (IEdmEntitySet)entityContainer.Elements.ElementAt(1);

            Assert.AreEqual("DuplicateEntityType", entitySetElement2.Name, "Invalid entity set name");
            Assert.AreEqual("TestModel.DuplicateEntityType", entitySetElement2.EntityType().FullName(), "Invalid entity set element type");

            Assert.IsTrue(model.SchemaElements.Count() == 3, "Invalid schema element count");
            Assert.AreEqual(EdmSchemaElementKind.TypeDefinition, model.SchemaElements.ElementAt(0).SchemaElementKind, "Invalid schema element kind");
            Assert.AreEqual(EdmSchemaElementKind.TypeDefinition, model.SchemaElements.ElementAt(1).SchemaElementKind, "Invalid schema element kind");

            IEdmEntityType entityTypeElement1 = (IEdmEntityType)model.SchemaElements.ElementAt(0);

            Assert.AreEqual("TestModel.DuplicateEntityType", entityTypeElement1.FullName(), "Invalid entity type full name");
            Assert.AreEqual("DuplicateEntityType", entityTypeElement1.Name, "Invalid entity type name");
            Assert.IsTrue(entityTypeElement1.Properties().Count() == 1, "Invalid property count");
            Assert.AreEqual("Id", entityTypeElement1.Properties().Single().Name, "Invalid property name");
            Assert.IsTrue(entityTypeElement1.DeclaredKey.Count() == 1, "Invalid declare key count for entity type");

            IEdmEntityType entityTypeElement2 = (IEdmEntityType)model.SchemaElements.ElementAt(1);

            Assert.AreEqual("TestModel.DuplicateEntityType", entityTypeElement2.FullName(), "Invalid entity type full name");
            Assert.AreEqual("DuplicateEntityType", entityTypeElement2.Name, "Invalid entity type name");
            Assert.IsTrue(entityTypeElement2.Properties().Count() == 1, "Invalid property count");
            Assert.AreEqual("Id", entityTypeElement2.Properties().Single().Name, "Invalid property name");
            Assert.IsTrue(entityTypeElement2.DeclaredKey.Count() == 1, "Invalid declare key count for entity type");

            var expectedErrors = new EdmLibTestErrors()
            {
                { 5, 10, EdmErrorCode.DuplicateEntityContainerMemberName },
                { 13, 6, EdmErrorCode.AlreadyDefined },
                { 4, 10, EdmErrorCode.BadUnresolvedEntityType },
                { 5, 10, EdmErrorCode.BadUnresolvedEntityType }
            };

            IEnumerable <EdmError> actualErrors = null;

            model.Validate(out actualErrors);
            this.CompareErrors(actualErrors, expectedErrors);
        }
예제 #19
0
        public static IEdmModel GetActionsModel(HttpConfiguration config)
        {
            ODataModelBuilder builder         = new ODataConventionModelBuilder(config);
            var baseEntitySet                 = builder.EntitySet <BaseEntity>("BaseEntity");
            var alwaysAvailableActionBaseType = baseEntitySet.EntityType.Action("AlwaysAvailableActionBaseType");
            var transientActionBaseType       = baseEntitySet.EntityType.TransientAction("TransientActionBaseType");
            Func <EntityInstanceContext, Uri> transientActionBaseTypeLinkFactory = eic =>
            {
                IEdmEntityType baseType = eic.EdmModel.FindType(typeof(BaseEntity).FullName) as IEdmEntityType;
                object         id;
                eic.EdmObject.TryGetPropertyValue("Id", out id);
                if (!eic.EntityType.IsOrInheritsFrom(baseType) || (int)id % 2 == 1)
                {
                    return(null);
                }
                else
                {
                    IList <ODataPathSegment> segments = new List <ODataPathSegment>();
                    segments.Add(new EntitySetPathSegment(eic.EntitySet));
                    segments.Add(new KeyValuePathSegment(id.ToString()));
                    segments.Add(new ActionPathSegment("TransientActionBaseType"));
                    string link = eic.Url.CreateODataLink("Actions", eic.Request.ODataProperties().PathHandler, segments);
                    return(new Uri(link));
                }
            };

            transientActionBaseType.HasActionLink(transientActionBaseTypeLinkFactory, true);
            var derivedEntityType = builder.Entity <DerivedEntity>().DerivesFrom <BaseEntity>();
            var alwaysAvailableActionDerivedType = derivedEntityType.Action("AlwaysAvailableActionDerivedType");
            var transientActionDerivedType       = derivedEntityType.TransientAction("TransientActionDerivedType");
            Func <EntityInstanceContext, Uri> transientActionDerivedTypeLinkFactory = eic =>
            {
                IEdmEntityType derivedType = eic.EdmModel.FindType(typeof(DerivedEntity).FullName) as IEdmEntityType;
                object         id;
                eic.EdmObject.TryGetPropertyValue("Id", out id);
                if (!eic.EntityType.IsOrInheritsFrom(derivedType) || (int)id % 2 == 1)
                {
                    return(null);
                }
                else
                {
                    IList <ODataPathSegment> segments = new List <ODataPathSegment>();
                    segments.Add(new EntitySetPathSegment(eic.EntitySet));
                    segments.Add(new KeyValuePathSegment(id.ToString()));
                    segments.Add(new CastPathSegment(derivedType.FullName()));
                    segments.Add(new ActionPathSegment("TransientActionDerivedType"));
                    string link = eic.Url.CreateODataLink("Actions", eic.Request.ODataProperties().PathHandler, segments);
                    return(new Uri(link));
                }
            };

            transientActionDerivedType.HasActionLink(transientActionDerivedTypeLinkFactory, true);
            return(builder.GetEdmModel());
        }
예제 #20
0
        private bool TryGetEntityTypeWrapperFor(IEdmEntityType innerEntityType, out EdmEntityTypeWrapper entityTypeWrapper)
        {
            if (innerEntityType != null)
            {
                string typeFullName = innerEntityType.FullName();
                return(_fixedTypes.TryGetValue(typeFullName, out entityTypeWrapper));
            }

            entityTypeWrapper = null;
            return(false);
        }
예제 #21
0
        internal EntityTypeInfo(IEdmModel edmModel, IEdmEntityType edmEntityType, ITypeResolver typeResolver)
        {
            Contract.Assert(edmModel != null);
            Contract.Assert(edmEntityType != null);
            Contract.Assert(typeResolver != null);

            _edmEntityType = edmEntityType;
            string edmTypeName = edmEntityType.FullName();
            _type = typeResolver.ResolveTypeFromName(edmTypeName);

            // Initialize DontSerializeProperties
            _dontSerializeProperties = _type.GetProperties().Where(p => p.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), true).Length > 0).Select(p => p.Name).ToArray();

            //edmEntityType.DeclaredKey;
            //edmEntityType.BaseEntityType();
            var structuralProperties = new List<PropertyInfo>();
            foreach (var edmStructuralProperty in edmEntityType.StructuralProperties())
            {
                if (! _dontSerializeProperties.Contains(edmStructuralProperty.Name))
                {
                    structuralProperties.Add(_type.GetProperty(edmStructuralProperty.Name));
                }
            }

            // EF can pick up private properties (eg: those marked as navigational).  We omit them on spec.
            _structuralProperties = structuralProperties.Where(p => p != null).ToArray();

            var navigationProperties = new List<PropertyInfo>();
            var linkProperties = new List<PropertyInfo>();
            foreach (var edmNavigationProperty in edmEntityType.NavigationProperties())
            {
                if (! _dontSerializeProperties.Contains(edmNavigationProperty.Name))
                {
                    if (edmNavigationProperty.Type.IsCollection())
                    {
                        linkProperties.Add(_type.GetProperty(edmNavigationProperty.Name));
                    }
                    else
                    {
                        navigationProperties.Add(_type.GetProperty(edmNavigationProperty.Name));
                    }
                }
            }
            _navigationProperties = navigationProperties.Where(p => p != null).ToArray();
            _collectionProperties = linkProperties.Where(p => p != null).ToArray();

            // Reflect for ValidationAttributes on all properties
            var validationInfo = new List<PropertyValidationInfo>();
            InitValidationInfo(validationInfo, _structuralProperties, PropertyCategory.Structural);
            InitValidationInfo(validationInfo, _navigationProperties, PropertyCategory.Navigation);
            InitValidationInfo(validationInfo, _collectionProperties, PropertyCategory.Collection);
            _propertyValidationInfo = validationInfo.ToArray();
        }
예제 #22
0
        private static IEnumerable <KeyValuePair <string, object> > GetPropertyValues(IEnumerable <IEdmStructuralProperty> properties, ODataResourceBase resource, IEdmEntityType actualEntityType, bool isRequired)
        {
            string actualEntityTypeName = actualEntityType.FullName();
            object primitiveValue;

            foreach (IEdmStructuralProperty property in properties)
            {
                if (TryGetPrimitiveOrEnumPropertyValue(resource, property.Name, actualEntityTypeName, isRequired, out primitiveValue))
                {
                    yield return(new KeyValuePair <string, object>(property.Name, primitiveValue));
                }
            }
        }
        private static PropertyInfo GetTuplePropertyByEntityType(Type tupleType, IEdmEntityType edmEntityType)
        {
            String fullName = edmEntityType.FullName();

            foreach (PropertyInfo propertyInfo in tupleType.GetProperties())
            {
                if (propertyInfo.PropertyType.FullName == fullName)
                {
                    return(propertyInfo);
                }
            }

            return(null);
        }
예제 #24
0
        private static PropertyInfo GetTuplePropertyByEntityType(Type tupleType, IEdmEntityType edmEntityType)
        {
            String fullName = edmEntityType.FullName();

            foreach (PropertyInfo propertyInfo in tupleType.GetTypeInfo().GetProperties())
            {
                if (propertyInfo.PropertyType.FullName == fullName)
                {
                    return(propertyInfo);
                }
            }

            throw new InvalidOperationException("entity type " + fullName + " not found in tuple properties");
        }
예제 #25
0
        private EntityInstance CreateEntityInstance(IEdmEntityType edmEntityType)
        {
            EntityInstance entity = new EntityInstance(edmEntityType.FullName(), false);

            foreach (var property in edmEntityType.Properties())
            {
                if (!(property is IEdmNavigationProperty))
                {
                    entity.Property(this.BuildProperty(property));
                }
            }

            return(entity);
        }
예제 #26
0
        private void CompareEntityType(IEdmEntityType expectedEntityType, IEdmEntityType actualEntityType)
        {
            this.SatisfiesEquals(expectedEntityType.FullName(), actualEntityType.FullName(), "EntityType name does not match.");
            this.SatisfiesEquals(expectedEntityType.IsAbstract, actualEntityType.IsAbstract, "IsAbstract does not match for EntityType '{0}'.", expectedEntityType.FullName());

            string expectedBaseTypeName = expectedEntityType.BaseType != null ? ((IEdmSchemaElement)expectedEntityType.BaseType).FullName() : null;
            string actualBaseTypeName   = actualEntityType.BaseType != null ? ((IEdmSchemaElement)actualEntityType.BaseType).FullName() : null;

            this.SatisfiesEquals(expectedBaseTypeName, actualBaseTypeName, "BaseType does not match for EntityType '{0}'.", expectedEntityType.FullName());
            this.CompareProperties(expectedEntityType.StructuralProperties().Cast <IEdmProperty>(), actualEntityType.StructuralProperties().Cast <IEdmProperty>());
            this.CompareProperties(expectedEntityType.Key().OfType <IEdmProperty>(), actualEntityType.Key().OfType <IEdmProperty>());
            this.CompareNavigationProperty(expectedEntityType.Properties().OfType <IEdmNavigationProperty>(), actualEntityType.Properties().OfType <IEdmNavigationProperty>());

            this.CompareTermAnnotations(expectedEntityType, actualEntityType);
        }
예제 #27
0
        private void ReadEntityType(IEdmEntityType entityType)
        {
            if (IsIgnored(entityType)) return;
            var typeUri = GetUriMapping(entityType);
            var identifierPrefix = GetIdentifierPrefix(entityType);

            _typeUriMap[entityType.FullName()] = new TypeMapping
                {
                    Uri = typeUri,
                    IdentifierPrefix = identifierPrefix
                };
            foreach (IEdmProperty property in entityType.Properties())
            {
                ReadProperty(entityType, property);
            }
        }
        private static string GetElementTypeName(IEdmEntitySet entitySet)
        {
            if (entitySet == null)
            {
                return(null);
            }

            IEdmEntityType elementType = entitySet.ElementType;

            if (elementType == null)
            {
                return(null);
            }

            return(elementType.FullName());
        }
예제 #29
0
        private void FillStockContentsForEntityWithoutNavigation(IEdmEntityType edmType, IEdmModel edmModel, EdmModel stockModel)
        {
            var stockType = (EdmEntityType)stockModel.FindType(edmType.FullName());

            this.SetImmediateAnnotations(edmType, stockType, edmModel, stockModel);

            foreach (var edmProperty in edmType.DeclaredStructuralProperties())
            {
                ConvertToStockStructuralProperty((IEdmStructuralProperty)edmProperty, edmModel, stockModel);
            }

            if (edmType.DeclaredKey != null)
            {
                stockType.AddKeys(edmType.DeclaredKey.Select(n => stockType.FindProperty(n.Name) as IEdmStructuralProperty).ToArray());
            }
        }
예제 #30
0
        public void GetSingleEntityEntityType_ReturnsEntityTypeForSingleEntityResources(string odataPath, string typeName)
        {
            // Arrange
            IEdmModel         model       = SetupModel();
            IODataPathHandler pathHandler = new DefaultODataPathHandler();
            ODataPath         path        = pathHandler.Parse(model, "http://localhost/any", odataPath);

            // Guard
            Assert.NotNull(path);

            // Act
            IEdmEntityType entityType = ETagMessageHandler.GetSingleEntityEntityType(path);

            // Assert
            Assert.NotNull(entityType);
            Assert.Equal(typeName, entityType.FullName());
        }
예제 #31
0
        private Type ConvertIEdmEntityTypeToClr(IEdmEntityType edmEntityType, DbContext context)
        {
            var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
            var oSpace   = metadata.GetItemCollection(DataSpace.OSpace);
            var typeName = oSpace.GetItems <EntityType>().Select(e => e.FullName).FirstOrDefault(name =>
            {
                var fullname = name + ":" + edmEntityType.FullName();
                MappingBase map;
                return(metadata.TryGetItem(fullname, DataSpace.OCSpace, out map));
            });

            if (typeName != null)
            {
                return(Type.GetType(typeName, null, GetTypeFromAssembly, false, false));
            }
            return(null);
        }
예제 #32
0
        /// <summary>
        /// Adds the derived types references together with their base type reference in the OneOf property of an OpenAPI schema.
        /// </summary>
        /// <returns>The OpenAPI schema with the list of derived types references and their base type references set in the OneOf property.</returns>
        internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmEntityType entityType, IEdmModel edmModel)
        {
            Utils.CheckArgumentNull(entityType, nameof(entityType));
            Utils.CheckArgumentNull(edmModel, nameof(edmModel));

            IEnumerable <IEdmEntityType> derivedTypes = edmModel.FindDirectlyDerivedTypes(entityType).OfType <IEdmEntityType>();

            if (!derivedTypes.Any())
            {
                return(null);
            }

            OpenApiSchema schema = new OpenApiSchema
            {
                OneOf = new List <OpenApiSchema>()
            };

            OpenApiSchema baseTypeSchema = new OpenApiSchema
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.Schema,
                    Id   = entityType.FullName()
                }
            };

            schema.OneOf.Add(baseTypeSchema);

            foreach (IEdmEntityType derivedType in derivedTypes)
            {
                OpenApiSchema derivedTypeSchema = new OpenApiSchema
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.Schema,
                        Id   = derivedType.FullName()
                    }
                };
                schema.OneOf.Add(derivedTypeSchema);
            }
            ;

            return(schema);
        }
예제 #33
0
        private void ReadEntityType(IEdmEntityType entityType)
        {
            if (IsIgnored(entityType))
            {
                return;
            }
            var typeUri          = GetUriMapping(entityType);
            var identifierPrefix = GetIdentifierPrefix(entityType);

            _typeUriMap[entityType.FullName()] = new TypeMapping
            {
                Uri = typeUri,
                IdentifierPrefix = identifierPrefix
            };
            foreach (IEdmProperty property in entityType.Properties())
            {
                ReadProperty(entityType, property);
            }
        }
예제 #34
0
        // OData formatter requires the type name of the entity that is being written if the type has derived types.
        // Expression
        //      source is GrandChild ? "GrandChild" : ( source is Child ? "Child" : "Root" )
        // Notice that the order is important here. The most derived type must be the first to check.
        // If entity framework had a way to figure out the type name without selecting the whole object, we don't have to do this magic.
        internal static Expression CreateTypeNameExpression(Expression source, IEdmEntityType elementType, IEdmModel model)
        {
            IReadOnlyList<IEdmEntityType> derivedTypes = GetAllDerivedTypes(elementType, model);

            if (derivedTypes.Count == 0)
            {
                // no inheritance.
                return null;
            }
            else
            {
                Expression expression = Expression.Constant(elementType.FullName());
                for (int i = 0; i < derivedTypes.Count; i++)
                {
                    Type clrType = EdmLibHelpers.GetClrType(derivedTypes[i], model);
                    if (clrType == null)
                    {
                        throw new ODataException(Error.Format(SRResources.MappingDoesNotContainEntityType, derivedTypes[0].FullName()));
                    }

                    expression = Expression.Condition(
                                    test: Expression.TypeIs(source, clrType),
                                    ifTrue: Expression.Constant(derivedTypes[i].FullName()),
                                    ifFalse: expression);
                }

                return expression;
            }
        }
예제 #35
0
        internal static string GetJsonPayload(IEdmEntityType entityType, object value)
        {
            Type valueType = value.GetType();
            StringBuilder sb = new StringBuilder();
            sb.Append("{");
            sb.Append(Environment.NewLine);
            sb.Append("\t");
            sb.Append("@odata.type: \"" + entityType.FullName() + "\",");
            var properties = entityType.StructuralProperties().ToList();
            for (int i = 0; i < properties.Count; i++)
            {
                sb.Append("\t");
                IEdmProperty property = properties[i];
                // Type propertyType = ((PrimitiveType)property.TypeUsage.EdmType).ClrEquivalentType;
                PropertyInfo propertyInfo = valueType.GetProperty(property.Name);
                Type propertyType = propertyInfo.PropertyType;
                propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;            
                object propertyValue = propertyInfo.GetValue(value, null);
                sb.Append(String.Format("{0}:{1}", properties[i].Name, PrimitiveToString(propertyValue, propertyType)));
                if (i != properties.Count - 1)
                {
                    sb.Append(",");
                }
                sb.Append(Environment.NewLine);
            }
            sb.Append("}");

            return sb.ToString();
        }
 public UnresolvedNavigationPropertyPath(IEdmEntityType startingType, string path, EdmLocation location)
     : base(startingType, path, new[] { new EdmError(location, EdmErrorCode.BadUnresolvedNavigationPropertyPath, Edm.Strings.Bad_UnresolvedNavigationPropertyPath(path, startingType.FullName())) })
 {
 }
        /// <summary>
        /// Verifies that CreateEntryReader or CreateFeedReader or CreateDeltaReader can be called.
        /// </summary>
        /// <param name="navigationSource">The navigation source we are going to read entities for.</param>
        /// <param name="entityType">The expected entity type for the entry/entries to be read.</param>
        private void VerifyCanCreateODataReader(IEdmNavigationSource navigationSource, IEdmEntityType entityType)
        {
            Debug.Assert(navigationSource == null || entityType != null, "If an navigation source is specified, the entity type must be specified as well.");

            // We require metadata information for reading requests.
            if (!this.ReadingResponse)
            {
                this.VerifyUserModel();

                if (navigationSource == null)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightInputContext_NoEntitySetForRequest);
                }
            }

            // We only check that the base type of the entity set is assignable from the specified entity type.
            // If no entity set/entity type is specified in the API, we will read it from the context URI.
            IEdmEntityType entitySetElementType = this.EdmTypeResolver.GetElementType(navigationSource);
            if (navigationSource != null && entityType != null && !entityType.IsOrInheritsFrom(entitySetElementType))
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightInputContext_EntityTypeMustBeCompatibleWithEntitySetBaseType(entityType.FullName(), entitySetElementType.FullName(), navigationSource.FullNavigationSourceName()));
            }
        }
        /// <summary>
        /// Get key value pair array for specifc odata entry using specifc entity type
        /// </summary>
        /// <param name="entry">The entry instance.</param>
        /// <param name="serializationInfo">The serialization info of the entry for writing without model.</param>
        /// <param name="actualEntityType">The edm entity type of the entry</param>
        /// <returns>Key value pair array</returns>
        internal static KeyValuePair<string, object>[] GetKeyProperties(
            ODataEntry entry,
            ODataFeedAndEntrySerializationInfo serializationInfo,
            IEdmEntityType actualEntityType)
        {
            KeyValuePair<string, object>[] keyProperties = null;
            string actualEntityTypeName = null;

            if (serializationInfo != null)
            {
                if (String.IsNullOrEmpty(entry.TypeName))
                {
                    throw new ODataException(OData.Core.Strings.ODataFeedAndEntryTypeContext_ODataEntryTypeNameMissing);
                }

                actualEntityTypeName = entry.TypeName;
                keyProperties = ODataEntryMetadataContextWithoutModel.GetPropertiesBySerializationInfoPropertyKind(entry, ODataPropertyKind.Key, actualEntityTypeName);
            }
            else
            {
                actualEntityTypeName = actualEntityType.FullName();

                IEnumerable<IEdmStructuralProperty> edmKeyProperties = actualEntityType.Key();
                if (edmKeyProperties != null)
                {
                    keyProperties = edmKeyProperties.Select(p => new KeyValuePair<string, object>(p.Name, GetPrimitivePropertyClrValue(entry, p.Name, actualEntityTypeName, /*isKeyProperty*/false))).ToArray();
                }
            }

            ValidateEntityTypeHasKeyProperties(keyProperties, actualEntityTypeName);
            return keyProperties;
        }
예제 #39
0
        private EdmEntityType ConstructStockEntityTypeInModel(IEdmEntityType entityType, EdmModel stockModel, Dictionary<string, EdmEntityType> stockEntityTypes)
        {
            EdmEntityType stockType;
            string fullName = entityType.FullName();
            if (!stockEntityTypes.TryGetValue(fullName, out stockType))
            {
                stockType = new EdmEntityType(
                    entityType.Namespace,
                    entityType.Name,
                    entityType.BaseType != null ? this.ConstructStockEntityTypeInModel((IEdmEntityType)entityType.BaseType, stockModel, stockEntityTypes) : null,
                    entityType.IsAbstract,
                    entityType.IsOpen);

                // TODO: IsBad, Documentation
                stockModel.AddElement(stockType);
                stockEntityTypes.Add(fullName, stockType);
            }

            return stockType;
        }
예제 #40
0
        private void FillStockContentsForEntityWithoutNavigation(IEdmEntityType edmType, IEdmModel edmModel, EdmModel stockModel)
        {
            var stockType = (EdmEntityType)stockModel.FindType(edmType.FullName());
            this.SetImmediateAnnotations(edmType, stockType, edmModel, stockModel);

            foreach (var edmProperty in edmType.DeclaredStructuralProperties())
            {
                ConvertToStockStructuralProperty((IEdmStructuralProperty)edmProperty, edmModel, stockModel);
            }

            if (edmType.DeclaredKey != null)
            {
                stockType.AddKeys(edmType.DeclaredKey.Select(n => stockType.FindProperty(n.Name) as IEdmStructuralProperty).ToArray());
            }
        }
예제 #41
0
        private void CreateNavigationPropertiesForStockEntity(IEdmEntityType edmType, IEdmModel edmModel, EdmModel stockModel)
        {
            var stockType = (EdmEntityType)stockModel.FindType(edmType.FullName());

            foreach (var edmNavigation in edmType.DeclaredNavigationProperties())
            {
                var stockToRoleType = (EdmEntityType)stockModel.FindType(edmNavigation.ToEntityType().FullName());

                if (stockType.FindProperty(edmNavigation.Name) == null)
                {
                    Func<IEnumerable<IEdmStructuralProperty>, IEnumerable<IEdmStructuralProperty>> createDependentProperties = (dependentProps) =>
                    {
                        if (dependentProps == null)
                        {
                            return null;
                        }

                        var stockDependentProperties = new List<IEdmStructuralProperty>();
                        foreach (var dependentProperty in dependentProps)
                        {
                            var stockDepProp = edmNavigation.DependentProperties() != null ? stockType.FindProperty(dependentProperty.Name) : stockToRoleType.FindProperty(dependentProperty.Name);
                            stockDependentProperties.Add((IEdmStructuralProperty)stockDepProp);
                        }

                        return stockDependentProperties;
                    };

                    Func<IEdmReferentialConstraint, IEdmEntityType, IEnumerable<IEdmStructuralProperty>> createPrincipalProperties = (refConstraint, principalType) =>
                    {
                        if (refConstraint == null)
                        {
                            return null;
                        }

                        return refConstraint.PropertyPairs.Select(p => (IEdmStructuralProperty)principalType.FindProperty(p.PrincipalProperty.Name));
                    };

                    var propertyInfo = new EdmNavigationPropertyInfo()
                        {
                            Name = edmNavigation.Name,
                            Target = stockToRoleType,
                            TargetMultiplicity = edmNavigation.TargetMultiplicity(),
                            DependentProperties = createDependentProperties(edmNavigation.DependentProperties()),
                            PrincipalProperties = createPrincipalProperties(edmNavigation.ReferentialConstraint, stockToRoleType),
                            ContainsTarget = edmNavigation.ContainsTarget,
                            OnDelete = edmNavigation.OnDelete
                        };

                    bool bidirectional = edmNavigation.Partner != null && edmNavigation.ToEntityType().FindProperty(edmNavigation.Partner.Name) != null;
                    if (bidirectional)
                    {
                        var partnerInfo = new EdmNavigationPropertyInfo()
                        {
                            Name = edmNavigation.Partner.Name,
                            TargetMultiplicity = edmNavigation.Partner.TargetMultiplicity(), 
                            DependentProperties = createDependentProperties(edmNavigation.Partner.DependentProperties()),
                            PrincipalProperties = createPrincipalProperties(edmNavigation.Partner.ReferentialConstraint, stockType),
                            ContainsTarget = edmNavigation.Partner.ContainsTarget, 
                            OnDelete = edmNavigation.Partner.OnDelete
                        };

                        stockType.AddBidirectionalNavigation(propertyInfo, partnerInfo);
                    }
                    else
                    {
                        stockType.AddUnidirectionalNavigation(propertyInfo);
                    }
                }
            }
        }
예제 #42
0
        private void ReadProperty(IEdmEntityType entityType, IEdmProperty property)
        {
            string declaredPropertyName;
            string entityPropertyName = entityType.FullName() + "." + property.Name;
            if (property.DeclaringType is IEdmEntityType)
            {
                declaredPropertyName = (property.DeclaringType as IEdmEntityType).FullName() + "." + property.Name;
            }
            else
            {
                declaredPropertyName = entityPropertyName;
            }

            PropertyMapping mapping;
            if (_propertyUriMap.TryGetValue(declaredPropertyName, out mapping))
            {
                _propertyUriMap[entityPropertyName] = mapping;
            }
            else
            {
                mapping = new PropertyMapping
                    {
                        Uri = GetUriMapping(property),
                        IsInverse = GetBooleanAnnotationValue(property, AnnotationsNamespace, "IsInverse", false),
                        IdentifierPrefix = GetStringAnnotationValue(property, AnnotationsNamespace, "IdentifierPrefix")
                    };
                // If the property maps to the resource identifier, do not record a property URI 
                if (!String.IsNullOrEmpty(mapping.IdentifierPrefix))
                {
                    mapping.Uri = null;
                }

                _propertyUriMap[entityPropertyName] = mapping;
                if (!declaredPropertyName.Equals(entityPropertyName))
                {
                    _propertyUriMap[declaredPropertyName] = mapping;
                }
            }
        }
예제 #43
0
        /// <summary>
        /// Asserts that a given entity type is derived from the specified base entity type.
        /// </summary>
        /// <param name="derivedType">The derived entity type.</param>
        /// <param name="baseType">The base entity type.</param>
        public static void AssertEntityTypeIsDerivedFrom(IEdmEntityType derivedType, IEdmEntityType baseType)
        {
            ExceptionUtilities.CheckArgumentNotNull(derivedType, "derivedType");
            ExceptionUtilities.CheckArgumentNotNull(baseType, "baseType");

            if (derivedType == baseType)
            {
                return;
            }

            var entityType = derivedType.BaseEntityType();
            while (entityType != null)
            {
                if (entityType == baseType)
                {
                    return;
                }

                entityType = entityType.BaseEntityType();
            }

            ExceptionUtilities.Assert(false, "Expected entity type " + derivedType.FullName() + " to be derived from " + baseType.FullName());
        }
예제 #44
0
 public string GetUriForProperty(IEdmEntityType entityType, string propertyName)
 {
     return GetUriForProperty(entityType.FullName(), propertyName);
 }
예제 #45
0
 private string GetIdentifierPrefix(IEdmEntityType entityType)
 {
     if (entityType.BaseEntityType() != null)
     {
         return GetIdentifierPrefix(entityType.BaseEntityType());
     }
     TypeMapping existingMapping;
     if (_typeUriMap.TryGetValue(entityType.FullName(), out existingMapping))
     {
         return existingMapping.IdentifierPrefix;
     }
     var keyList = entityType.DeclaredKey.ToList();
     if (keyList.Count != 1)
     {
         // Ignore this entity
         // TODO: Log an error
         return null;
     }
     var identifierPrefix = GetStringAnnotationValue(keyList.First(), AnnotationsNamespace, "IdentifierPrefix");
     if (identifierPrefix == null)
     {
         // TODO: Log an error
     }
     return identifierPrefix;
 }
예제 #46
0
        internal static bool ShouldSuppressTypeNameSerialization(ODataEntry entry, IEdmEntityType edmType,
            ODataMetadataLevel metadataLevel)
        {
            Contract.Assert(entry != null);

            switch (metadataLevel)
            {
                case ODataMetadataLevel.NoMetadata:
                    return true;
                case ODataMetadataLevel.FullMetadata:
                    return false;
                case ODataMetadataLevel.MinimalMetadata:
                default: // All values already specified; just keeping the compiler happy.
                    string pathTypeName = null;
                    if (edmType != null)
                    {
                        pathTypeName = edmType.FullName();
                    }
                    string entryTypeName = entry.TypeName;
                    return String.Equals(entryTypeName, pathTypeName, StringComparison.Ordinal);
            }
        }
예제 #47
0
        private void CompareEntityType(IEdmEntityType expectedEntityType, IEdmEntityType actualEntityType)
        {
            this.SatisfiesEquals(expectedEntityType.FullName(), actualEntityType.FullName(), "EntityType name does not match.");
            this.SatisfiesEquals(expectedEntityType.IsAbstract, actualEntityType.IsAbstract, "IsAbstract does not match for EntityType '{0}'.", expectedEntityType.FullName());

            string expectedBaseTypeName = expectedEntityType.BaseType != null ? ((IEdmSchemaElement)expectedEntityType.BaseType).FullName() : null;
            string actualBaseTypeName = actualEntityType.BaseType != null ? ((IEdmSchemaElement)actualEntityType.BaseType).FullName() : null;

            this.SatisfiesEquals(expectedBaseTypeName, actualBaseTypeName, "BaseType does not match for EntityType '{0}'.", expectedEntityType.FullName());
            this.CompareProperties(expectedEntityType.StructuralProperties().Cast<IEdmProperty>(), actualEntityType.StructuralProperties().Cast<IEdmProperty>());
            this.CompareProperties(expectedEntityType.Key().OfType<IEdmProperty>(), actualEntityType.Key().OfType<IEdmProperty>());
            this.CompareNavigationProperty(expectedEntityType.Properties().OfType<IEdmNavigationProperty>(), actualEntityType.Properties().OfType<IEdmNavigationProperty>());

            this.CompareTermAnnotations(expectedEntityType, actualEntityType);
        }