private void AddPropertyToInterfaceFile(UnifiedModelEntity entity, List <PropertyDefinition> withAttributes, List <PropertyDefinition> withoutAttributes, StringBuilder propertiesString, UnifiedModelProperty property) { this.log.LogInformation($"Processing property '{property.Name}' of type '{entity.TypeName}'"); string propertyToAdd = LoadFile(ModelPropertyPublic); if (property.NavigationPropertyIsCollection) { Replace(ref propertyToAdd, PropertyTypeKey, $"I{RestTypeToCollectionName(property.Type)}"); } else if (property.NavigationProperty) { Replace(ref propertyToAdd, PropertyTypeKey, $"I{RestTypeToNavigationTypeName(property.Type)}"); } else { Replace(ref propertyToAdd, PropertyTypeKey, ShortenType(property.Type)); } if (withAttributes != null || withoutAttributes != null) { // Add attributes which where already defined previously var matchingProperty = withAttributes != null?FindMatchingPropertyBasedUponAttributes(withAttributes, "SharePointPropertyAttribute", property) : null; if (matchingProperty == null) { // Do we have match on the attribute usage properties based upon name (not all properties have the SharePointPropertyAttribute) matchingProperty = withAttributes != null?withAttributes.FirstOrDefault(p => p.Name == property.Name) : null; } if (matchingProperty == null) { matchingProperty = withoutAttributes != null?withoutAttributes.FirstOrDefault(p => p.Name == property.Name) : null; } if (matchingProperty != null) { Replace(ref propertyToAdd, PropertyNameKey, matchingProperty.Name); Replace(ref propertyToAdd, PropertyGetSetKey, property.NavigationProperty ? "get;" : PropertyDefinitionToGetSet(matchingProperty)); } else { Replace(ref propertyToAdd, PropertyNameKey, property.Name); Replace(ref propertyToAdd, PropertyGetSetKey, property.NavigationProperty ? "get;" : "get; set;"); } } else { Replace(ref propertyToAdd, PropertyNameKey, property.Name); Replace(ref propertyToAdd, PropertyGetSetKey, property.NavigationProperty ? "get;" : "get; set;"); } propertiesString.AppendLine(propertyToAdd); propertiesString.AppendLine(); }
private void AddCollectionToGenerate(UnifiedModelEntity entity, UnifiedModelProperty property) { if (property.NavigationPropertyIsCollection) { var collectionName = RestTypeToCollectionName(property.Type); var collectionKey = $"{entity.Namespace}.{collectionName}"; if (!neededCollections.ContainsKey(collectionKey)) { neededCollections.Add(collectionKey, new CollectionInformation() { Name = collectionName, ModelType = RestTypeToNavigationTypeName(property.Type), Namespace = entity.Namespace, Folder = entity.Folder }); } } }
private async Task <UnifiedModel> ProcessProvider(UnifiedModelMapping mapping, KeyValuePair <string, XDocument> edmxDocumentInfo) { UnifiedModel model = new UnifiedModel { Provider = edmxDocumentInfo.Key }; Dictionary <string, AnalyzedModelType> analyzedModelTypes = new Dictionary <string, AnalyzedModelType>(); var edmxDocument = edmxDocumentInfo.Value; foreach (var location in mapping.Locations) { // Combine code information with information from the metadata into a model that will be used to drive code generation var edmxNamespace = (XNamespace)mapping.EdmxNamespace; var schemaNamespace = (XNamespace)mapping.SchemaNamespace; // Get information about the current code implementation var analyzedTypes = await codeAnalyzer.ProcessNamespace(location); analyzedTypes.ToList().ForEach(x => { if (!analyzedModelTypes.ContainsKey(x.Key)) { analyzedModelTypes.Add(x.Key, x.Value); } }); // Now process the properties from the EDMX providers var providerSchemaElements = edmxDocument.Descendants(schemaNamespace + "Schema").Where(e => e.Attribute("Namespace")?.Value == location.SchemaNamespace); foreach (var providerSchemaElement in providerSchemaElements) { //var providerEntities = providerSchemaElement.Elements(schemaNamespace + "EntityType").Where(e => e.Attribute("Name")?.Value == "Web"); var providerEntities = providerSchemaElement.Elements(schemaNamespace + "EntityType"); foreach (var providerEntity in providerEntities) { UnifiedModelEntity entity = new UnifiedModelEntity { TypeName = providerEntity.Attribute("Name").Value, Namespace = location.Namespace, SchemaNamespace = location.SchemaNamespace, Folder = location.Folder, SPRestType = $"{providerSchemaElement.Attribute("Namespace").Value}.{providerEntity.Attribute("Name").Value}", BaseType = providerEntity.Attribute("BaseType")?.Value }; // Process simple properties foreach (var property in providerEntity.Elements(schemaNamespace + "Property")) { var propertyNameAttribute = property.Attribute("Name"); var propertyTypeAttribute = property.Attribute("Type"); if (propertyNameAttribute != null && propertyTypeAttribute != null) { var propertyName = NormalizePropertyName(propertyNameAttribute.Value); var propertyType = ResolvePropertyType(propertyTypeAttribute.Value); if (propertyType != null) { UnifiedModelProperty modelProp = new UnifiedModelProperty() { Name = propertyName, Type = propertyType, NavigationProperty = false }; entity.Properties.Add(modelProp); } } } // Process navigation properties foreach (var property in providerEntity.Elements(schemaNamespace + "NavigationProperty")) { //<NavigationProperty Name="Alerts" Relationship="SP.SP_Web_Alerts_SP_Alert_AlertsPartner" ToRole="Alerts" FromRole="AlertsPartner" /> var propertyNameAttribute = property.Attribute("Name"); var propertyRelationshipAttribute = property.Attribute("Relationship"); var propertyToRoleAttribute = property.Attribute("ToRole"); if (propertyNameAttribute != null && propertyRelationshipAttribute != null && propertyToRoleAttribute != null) { var propertyName = NormalizePropertyName(propertyNameAttribute.Value); if (propertyName != null) { // Find associationset: //<AssociationSet Name="SP_Web_Alerts_SP_Alert_AlertsPartnerSet" Association="SP.SP_Web_Alerts_SP_Alert_AlertsPartner"> // <End Role="AlertsPartner" EntitySet="Webs" /> // <End Role="Alerts" EntitySet="Alerts" /> //</AssociationSet> var associatedSet = edmxDocument.Descendants(schemaNamespace + "AssociationSet").FirstOrDefault(e => e.Attribute("Association")?.Value == propertyRelationshipAttribute.Value); if (associatedSet != null) { // Find related association //<Association Name="SP_Web_Alerts_SP_Alert_AlertsPartner"> // <End Type="SP.Alert" Role="Alerts" Multiplicity="*" /> // <End Type="SP.Web" Role="AlertsPartner" Multiplicity="0..1" /> //</Association> //Remove namespace from association : SP.SP_Web_Alerts_SP_Alert_AlertsPartner can be found as SP_Web_Alerts_SP_Alert_AlertsPartner var associationNameToFind = associatedSet.Attribute("Association").Value.Substring(associatedSet.Attribute("Association").Value.LastIndexOf(".") + 1); var association = edmxDocument.Descendants(schemaNamespace + "Association").FirstOrDefault(e => e.Attribute("Name")?.Value == associationNameToFind); if (association != null) { // Find the needed "End" var associatedEnd = association.Elements(schemaNamespace + "End").FirstOrDefault(e => e.Attribute("Role")?.Value == propertyToRoleAttribute.Value); if (associatedEnd != null) { UnifiedModelProperty modelProp = new UnifiedModelProperty() { Name = propertyName, Type = associatedEnd.Attribute("Type").Value, // Multiplicity = * (collection) or 0..1 NavigationPropertyIsCollection = associatedEnd.Attribute("Multiplicity").Value.Equals("*"), NavigationProperty = true }; entity.Properties.Add(modelProp); } } } } } } model.Entities.Add(entity); } } // Combine with mapping file data if (mapping != null && mapping.ExcludedTypes != null) { foreach (var entityFromMapping in mapping.ExcludedTypes) { var typeToExclude = model.Entities.FirstOrDefault(p => p.SPRestType == entityFromMapping.Type); if (typeToExclude != null) { if (entityFromMapping.Properties.Any()) { foreach (var property in entityFromMapping.Properties) { var propertyToExclude = typeToExclude.Properties.FirstOrDefault(p => p.Name.Equals(property, StringComparison.InvariantCultureIgnoreCase)); if (propertyToExclude != null) { propertyToExclude.Skip = true; } } } else { // Exclude the complete type typeToExclude.Skip = true; } } } } // Hookup with the possibly available types in the PnP Core SDK foreach (var analyzedModelType in analyzedModelTypes) { if (analyzedModelType.Value.SPRestTypes.Any()) { foreach (var spRestType in analyzedModelType.Value.SPRestTypes) { var typeToUpdate = model.Entities.FirstOrDefault(p => p.SPRestType == spRestType); if (typeToUpdate != null) { typeToUpdate.AnalyzedModelType = analyzedModelType.Value; } } } } } return(model); }
private Tuple <List <UnifiedModelProperty>, List <UnifiedModelProperty> > OrderProperties(UnifiedModelEntity entity, List <PropertyDefinition> withAttributes, List <PropertyDefinition> withoutAttributes) { List <UnifiedModelProperty> existingProperties = new List <UnifiedModelProperty>(); List <UnifiedModelProperty> newProperties = new List <UnifiedModelProperty>(); foreach (var property in entity.Properties) { if (withAttributes != null || withoutAttributes != null) { // Try to match based upon attribute usage // e.g. Id edmx you have property Description // In code you have property DisplayName decorated with [SharePointType("Description")] var matchingProperty = withAttributes != null?FindMatchingPropertyBasedUponAttributes(withAttributes, "SharePointPropertyAttribute", property) : null; if (matchingProperty == null) { // Do we have match on the attribute usage properties based upon name (not all properties have the SharePointPropertyAttribute) matchingProperty = withAttributes != null?withAttributes.FirstOrDefault(p => p.Name == property.Name) : null; if (matchingProperty == null) { // Do we have a regular property? matchingProperty = withoutAttributes != null?withoutAttributes.FirstOrDefault(p => p.Name == property.Name) : null; } } if (matchingProperty != null) { existingProperties.Add(property); } else { newProperties.Add(property); } } else { newProperties.Add(property); } } return(new Tuple <List <UnifiedModelProperty>, List <UnifiedModelProperty> >(existingProperties, newProperties)); }
private void AddPropertyToClassFile(UnifiedModelEntity entity, List <PropertyDefinition> withAttributes, List <PropertyDefinition> withoutAttributes, StringBuilder propertiesString, UnifiedModelProperty property) { this.log.LogInformation($"Processing property '{property.Name}' of type '{entity.TypeName}'"); string baseProperty = ""; if (!property.NavigationProperty) { // Regular props baseProperty = LoadFile(ModelPropertyInternal); } else { // Navigation props if (property.NavigationPropertyIsCollection) { baseProperty = LoadFile(ModelNavigationCollectionPropertyInternal); } else { baseProperty = LoadFile(ModelNavigationPropertyInternal); } } var propertyToAdd = baseProperty.Replace(PropertyTypeKey, ShortenType(property.Type)); if (property.NavigationPropertyIsCollection) { var collectionName = RestTypeToCollectionName(property.Type); Replace(ref propertyToAdd, CollectionNameKey, collectionName); } else if (property.NavigationProperty) { Replace(ref propertyToAdd, NavigationTypeKey, RestTypeToNavigationTypeName(property.Type)); } string propertyAttributesString = ""; bool navigationPropertyAttributesAdded = false; if (withAttributes != null || withoutAttributes != null) { // Add attributes which where already defined previously var matchingProperty = withAttributes != null?FindMatchingPropertyBasedUponAttributes(withAttributes, "SharePointPropertyAttribute", property) : null; if (matchingProperty == null) { // Do we have match on the attribute usage properties based upon name (not all properties have the SharePointPropertyAttribute) matchingProperty = withAttributes != null?withAttributes.FirstOrDefault(p => p.Name == property.Name) : null; } if (matchingProperty != null) { foreach (var attr in matchingProperty.CustomAttributes) { navigationPropertyAttributesAdded = true; if (!string.IsNullOrEmpty(propertyAttributesString)) { propertyAttributesString += Environment.NewLine; } propertyAttributesString += CustomAttributeToCode(attr); } Replace(ref propertyToAdd, PropertyNameKey, matchingProperty.Name); AddCollectionToGenerate(entity, property); } else { Replace(ref propertyToAdd, PropertyNameKey, property.Name); AddCollectionToGenerate(entity, property); } } else { Replace(ref propertyToAdd, PropertyNameKey, property.Name); AddCollectionToGenerate(entity, property); } if (!navigationPropertyAttributesAdded) { // Add properties we know have to be there //if (property.NavigationPropertyIsCollection) //{ // propertyAttributesString = AddAttribute("SharePointProperty", $"\"{property.Name}\"", "Expandable = true"); //} } if (!string.IsNullOrEmpty(propertyAttributesString)) { Replace(ref propertyToAdd, PropertyAttributesKey, propertyAttributesString); } else { Replace(ref propertyToAdd, $"{PropertyAttributesKey}{Environment.NewLine}", propertyAttributesString); } propertiesString.AppendLine(propertyToAdd); propertiesString.AppendLine(); }
private void AddKeyPropertyToClassFile(UnifiedModelEntity entity, List <PropertyDefinition> withAttributes, StringBuilder propertiesString) { string keyPropertyField = ""; string keyPropertyType = ""; //if (withAttributes != null) //{ // bool found = false; // foreach (var existingProperty in withAttributes) // { // if (found) // { // break; // } // var attributesToCheck = existingProperty.CustomAttributes.Where(p => p.AttributeType.Name == "KeyPropertyAttribute"); // foreach (var attributeToCheck in attributesToCheck) // { // if (attributeToCheck.HasConstructorArguments) // { // keyPropertyField = attributeToCheck.ConstructorArguments[0].Value.ToString(); // keyPropertyType = ShortenType(attributeToCheck.ConstructorArguments[0].Type.Name); // found = true; // } // } // } //} if (string.IsNullOrEmpty(keyPropertyField)) { var property = entity.Properties.FirstOrDefault(p => p.Name == "Id"); if (property == null) { property = entity.Properties.FirstOrDefault(p => p.Name == "StringId"); } if (property != null) { keyPropertyField = property.Name; keyPropertyType = ShortenType(property.Type); } } if (!string.IsNullOrEmpty(keyPropertyField)) { var keyProperty = LoadFile(ModelKeyPropertyInternal); Replace(ref keyProperty, KeyPropertyNameKey, keyPropertyField); if (keyPropertyType == "Guid") { Replace(ref keyProperty, KeyPropertyValueKey, "Guid.Parse(value.ToString())"); } else if (keyPropertyType == "string") { Replace(ref keyProperty, KeyPropertyValueKey, "value.ToString()"); } else if (keyPropertyType == "int" || keyPropertyType == "Int32" || keyPropertyType == "Int64") { Replace(ref keyProperty, KeyPropertyValueKey, "(int)value"); } propertiesString.AppendLine(keyProperty); } }
private void GenerateModelFiles(UnifiedModelEntity entity) { //var classFileGen = LoadFile(ModelClassGenInternal); var classFile = LoadFile(ModelClassInternal); var interfaceFile = LoadFile(ModelClassPublic); Replace(ref classFile, TypeKey, entity.TypeName); Replace(ref classFile, NamespaceKey, entity.Namespace); Replace(ref classFile, RestTypeKey, entity.SPRestType); Replace(ref interfaceFile, TypeKey, entity.TypeName); Replace(ref interfaceFile, NamespaceKey, entity.Namespace); Tuple <List <PropertyDefinition>, List <PropertyDefinition> > splitExistingPropertiesImplementation = null; if (entity.AnalyzedModelType != null && entity.AnalyzedModelType.Implementation != null) { splitExistingPropertiesImplementation = SplitExistingPropertiesBasedUponAttribute(entity.AnalyzedModelType.Implementation); } Tuple <List <PropertyDefinition>, List <PropertyDefinition> > splitExistingPropertiesInterface = null; if (entity.AnalyzedModelType != null && entity.AnalyzedModelType.Public != null) { splitExistingPropertiesInterface = SplitExistingPropertiesBasedUponAttribute(entity.AnalyzedModelType.Public); } Tuple <List <UnifiedModelProperty>, List <UnifiedModelProperty> > orderedPropertiesImplementation = OrderProperties(entity, splitExistingPropertiesImplementation?.Item1, splitExistingPropertiesImplementation?.Item2); Tuple <List <UnifiedModelProperty>, List <UnifiedModelProperty> > orderedPropertiesInterface = OrderProperties(entity, splitExistingPropertiesInterface?.Item1, splitExistingPropertiesInterface?.Item2); StringBuilder classPropertiesString = new StringBuilder(); StringBuilder interfacePropertiesString = new StringBuilder(); if (orderedPropertiesImplementation.Item1.Any()) { classPropertiesString.AppendLine(" #region Existing properties"); classPropertiesString.AppendLine(); } if (orderedPropertiesInterface.Item1.Any()) { interfacePropertiesString.AppendLine(" #region Existing properties"); interfacePropertiesString.AppendLine(); } foreach (var property in orderedPropertiesImplementation.Item1) { if (!property.Skip) { AddPropertyToClassFile(entity, splitExistingPropertiesImplementation?.Item1, splitExistingPropertiesImplementation?.Item2, classPropertiesString, property); } else { log.LogInformation($"Property {property.Name} was skipped"); } } foreach (var property in orderedPropertiesInterface.Item1) { if (!property.Skip) { AddPropertyToInterfaceFile(entity, splitExistingPropertiesInterface?.Item1, splitExistingPropertiesInterface?.Item2, interfacePropertiesString, property); } else { log.LogInformation($"Property {property.Name} was skipped"); } } if (orderedPropertiesImplementation.Item1.Any()) { classPropertiesString.AppendLine(" #endregion"); classPropertiesString.AppendLine(); } classPropertiesString.AppendLine(" #region New properties"); classPropertiesString.AppendLine(); if (orderedPropertiesInterface.Item1.Any()) { interfacePropertiesString.AppendLine(" #endregion"); interfacePropertiesString.AppendLine(); } interfacePropertiesString.AppendLine(" #region New properties"); interfacePropertiesString.AppendLine(); foreach (var property in orderedPropertiesImplementation.Item2) { if (!property.Skip) { AddPropertyToClassFile(entity, splitExistingPropertiesImplementation?.Item1, splitExistingPropertiesImplementation?.Item2, classPropertiesString, property); } else { log.LogInformation($"Property {property.Name} was skipped"); } } foreach (var property in orderedPropertiesInterface.Item2) { if (!property.Skip) { AddPropertyToInterfaceFile(entity, splitExistingPropertiesInterface?.Item1, splitExistingPropertiesInterface?.Item2, interfacePropertiesString, property); } else { log.LogInformation($"Property {property.Name} was skipped"); } } classPropertiesString.AppendLine(" #endregion"); interfacePropertiesString.AppendLine(" #endregion"); AddKeyPropertyToClassFile(entity, splitExistingPropertiesImplementation?.Item1, classPropertiesString); Replace(ref classFile, PropertiesKey, classPropertiesString.ToString()); Replace(ref interfaceFile, PropertiesKey, interfacePropertiesString.ToString()); SaveFile(classFile, $"{entity.TypeName}.cs", entity.Folder, false); SaveFile(interfaceFile, $"I{entity.TypeName}.cs", entity.Folder, true); }