Beispiel #1
0
        private static EntityFieldInfo EnsureClassField(Type type, PropertyInfo property, EntityInfo classInfo)
        {
            var classField = classInfo.Fields.FirstOrDefault(p => p.Name.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase));

            if (classField == null)
            {
                classField = new EntityFieldInfo()
                {
                    Name         = property.Name,
                    DataType     = property.PropertyType,
                    PropertyInfo = type.GetProperty(property.Name),
                };
                classInfo.Fields.Add(classField);
            }

            if (classInfo.SharePointTargets.Any() && string.IsNullOrEmpty(classField.SharePointName))
            {
                // This type can be loaded via SharePoint REST, so ensure the SharePoint field is populated
                classField.SharePointName = property.Name;
            }

            return(classField);
        }
Beispiel #2
0
        /// <summary>
        /// Translates model type into a set of classes that are used to drive CRUD operations
        /// </summary>
        /// <param name="type">The reference model type</param>
        /// <returns>Entity model class describing this model instance</returns>
        internal EntityInfo GetStaticClassInfo(Type type)
        {
            type = GetEntityConcreteType(type);

            // Check if we can deliver this entity from cache
            if (entityCache.TryGetValue(type, out EntityInfo entityInfoFromCache))
            {
                return(entityInfoFromCache);
            }
            else
            {
                // Load and process type attributes
                var sharePointTypeAttributes = type.GetCustomAttributes <SharePointTypeAttribute>(false);
                var graphTypeAttributes      = type.GetCustomAttributes <GraphTypeAttribute>(false);

                if (sharePointTypeAttributes.Any() || graphTypeAttributes.Any())
                {
                    EntityInfo classInfo = new EntityInfo
                    {
                        UseOverflowField = type.ImplementsInterface(typeof(IExpandoDataModel))
                    };

                    if (sharePointTypeAttributes.Any())
                    {
                        foreach (var sharePointTypeAttribute in sharePointTypeAttributes)
                        {
                            var sharePointTargetToAdd = new EntitySharePointTypeInfo
                            {
                                Type             = sharePointTypeAttribute.Type,
                                Target           = sharePointTypeAttribute.Target ?? type,
                                Uri              = sharePointTypeAttribute.Uri,
                                Get              = !string.IsNullOrEmpty(sharePointTypeAttribute.Get) ? sharePointTypeAttribute.Get : sharePointTypeAttribute.Uri,
                                LinqGet          = !string.IsNullOrEmpty(sharePointTypeAttribute.LinqGet) ? sharePointTypeAttribute.LinqGet : sharePointTypeAttribute.Uri,
                                OverflowProperty = sharePointTypeAttribute.OverflowProperty,
                                Update           = !string.IsNullOrEmpty(sharePointTypeAttribute.Update) ? sharePointTypeAttribute.Update : sharePointTypeAttribute.Uri,
                                Delete           = !string.IsNullOrEmpty(sharePointTypeAttribute.Delete) ? sharePointTypeAttribute.Delete : sharePointTypeAttribute.Uri,
                            };

                            classInfo.SharePointTargets.Add(sharePointTargetToAdd);
                        }
                    }

                    if (graphTypeAttributes.Any())
                    {
                        foreach (var graphTypeAttribute in graphTypeAttributes)
                        {
                            var graphTargetToAdd = new EntityGraphTypeInfo
                            {
                                Target           = graphTypeAttribute.Target ?? type,
                                Id               = !string.IsNullOrEmpty(graphTypeAttribute.Id) ? graphTypeAttribute.Id : "id",
                                Get              = !string.IsNullOrEmpty(graphTypeAttribute.Get) ? graphTypeAttribute.Get : graphTypeAttribute.Uri,
                                LinqGet          = !string.IsNullOrEmpty(graphTypeAttribute.LinqGet) ? graphTypeAttribute.LinqGet : graphTypeAttribute.Uri,
                                OverflowProperty = graphTypeAttribute.OverflowProperty,
                                Update           = !string.IsNullOrEmpty(graphTypeAttribute.Update) ? graphTypeAttribute.Update : graphTypeAttribute.Uri,
                                Delete           = !string.IsNullOrEmpty(graphTypeAttribute.Delete) ? graphTypeAttribute.Delete : graphTypeAttribute.Uri,
                                Beta             = graphTypeAttribute.Beta,
                            };

                            classInfo.GraphTargets.Add(graphTargetToAdd);
                        }
                    }

                    string keyPropertyName = null;
                    foreach (var property in type.GetProperties())
                    {
                        EntityFieldInfo classField = null;

                        var  propertyAttributes = property.GetCustomAttributes();
                        bool skipField          = false;
                        foreach (var attribute in propertyAttributes)
                        {
                            switch (attribute)
                            {
                            // Field metadata
                            case SharePointPropertyAttribute sharePointPropertyAttribute:
                            {
                                classField = EnsureClassField(type, property, classInfo);
                                classField.SharePointName             = !string.IsNullOrEmpty(sharePointPropertyAttribute.FieldName) ? sharePointPropertyAttribute.FieldName : property.Name;
                                classField.ExpandableByDefault        = sharePointPropertyAttribute.ExpandByDefault;
                                classField.SharePointUseCustomMapping = sharePointPropertyAttribute.UseCustomMapping;
                                classField.SharePointJsonPath         = sharePointPropertyAttribute.JsonPath;
                                break;
                            }

                            case GraphPropertyAttribute graphPropertyAttribute:
                            {
                                classField                       = EnsureClassField(type, property, classInfo);
                                classField.GraphName             = !string.IsNullOrEmpty(graphPropertyAttribute.FieldName) ? graphPropertyAttribute.FieldName : ToCamelCase(property.Name);
                                classField.GraphExpandable       = graphPropertyAttribute.Expandable;
                                classField.ExpandableByDefault   = graphPropertyAttribute.ExpandByDefault;
                                classField.GraphUseCustomMapping = graphPropertyAttribute.UseCustomMapping;
                                classField.GraphJsonPath         = graphPropertyAttribute.JsonPath;
                                classField.GraphGet              = graphPropertyAttribute.Get;
                                classField.GraphBeta             = graphPropertyAttribute.Beta;
                                break;
                            }

                            case KeyPropertyAttribute keyPropertyAttribute:
                            {
                                keyPropertyName = keyPropertyAttribute.KeyPropertyName;
                                skipField       = true;
                                break;
                            }

                            case SystemPropertyAttribute systemPropertyAttribute:
                            {
                                skipField = true;
                                break;
                            }
                            }
                        }

                        if (!skipField)
                        {
                            if (classField == null)
                            {
                                classField = EnsureClassField(type, property, classInfo);
                                // Property was not decorated with attributes
                                if (!classInfo.SharePointTargets.Any())
                                {
                                    // This is a Graph only property
                                    classField.GraphName = ToCamelCase(property.Name);
                                }
                                else
                                {
                                    // This is SharePoint/Graph property, we're not setting the GraphName here because in "mixed" objects the Graph properties must be explicitely marked with the GraphProperty attribute
                                    classField.SharePointName = property.Name;
                                }
                            }

                            // Automatically determine "expand" value for SharePoint properties
                            if (!string.IsNullOrEmpty(classField.SharePointName))
                            {
                                if (JsonMappingHelper.IsModelCollection(classField.PropertyInfo.PropertyType) ||
                                    JsonMappingHelper.IsModelType(classField.PropertyInfo.PropertyType))
                                {
                                    classField.SharePointExpandable = true;
                                }
                            }
                        }
                    }

                    // Find the property set as key field and mark it as such
                    if (!string.IsNullOrEmpty(keyPropertyName))
                    {
                        // Store the actual key property name
                        classInfo.ActualKeyFieldName = keyPropertyName;

                        // Process the SharePoint and Graph ID fields
                        var keyProperty = classInfo.Fields.FirstOrDefault(p => p.Name == keyPropertyName);
                        if (keyProperty != null)
                        {
                            if (classInfo.SharePointTargets.Any())
                            {
                                keyProperty.IsSharePointKey = true;
                            }

                            keyProperty.IsGraphKey = true;
                            // If a property is defined as graph key then ensure the GraphName is correctly set
                            if (string.IsNullOrEmpty(keyProperty.GraphName) && classInfo.GraphTargets.Any())
                            {
                                keyProperty.GraphName = ToCamelCase(keyProperty.Name);
                            }
                        }
                    }

                    // Update the field used for overflow, this field was added (as it's part of the ExpandoBaseDataModel base data class),
                    // But since there's no field to set properties on the fieldname property comes from the class mapping attribute
                    if (classInfo.UseOverflowField)
                    {
                        var overflowField = classInfo.Fields.FirstOrDefault(p => p.Name == ExpandoBaseDataModel <IExpandoDataModel> .OverflowFieldName);

                        if (!classInfo.SharePointTargets.Any())
                        {
                            // This is a Graph only property
                            overflowField.GraphName = classInfo.GraphTargets.First().OverflowProperty;
                        }
                        else
                        {
                            // This is SharePoint/Graph property
                            overflowField.SharePointName = classInfo.SharePointTargets.First().OverflowProperty;
                            overflowField.GraphName      = classInfo.GraphTargets.FirstOrDefault()?.OverflowProperty;
                        }
                    }

                    // Add to our cache to speed up future retrievals
                    entityCache.TryAdd(type, classInfo);
                    return(classInfo);
                }
                else
                {
                    throw new ClientException(ErrorType.ModelMetadataIncorrect,
                                              PnPCoreResources.Exception_ModelMetadataIncorrect_MissingClassMapping);
                }
            }
        }