private static RelatedEntityInfo GetRelatedParentEntityInfo(CodeProperty property, IEnumerable<CodeProperty> allCandidateProperties, Project project, IProjectTypeLocator projectTypeLocator) { // First, we need to be able to extract "SomeType" from properties called "SomeTypeID" // "SomeType" is the name of the relation, and either corresponds to an entity type, or to another property whose type is an entity if (!property.Name.EndsWith(PropertySuffix, StringComparison.OrdinalIgnoreCase)) return null; var relationName = property.Name.Substring(0, property.Name.Length - PropertySuffix.Length); if (string.IsNullOrEmpty(relationName)) return null; // Next, "SomeType" needs to correspond to plausible entity or be the name of another property whose type is a plausible entity List<CodeType> foundRelatedEntityTypes; var propertyNameComparison = VsConstants.VbCodeModelLanguageGuid.Equals(property.Language, StringComparison.OrdinalIgnoreCase) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; var matchesOtherCandidateProperty = allCandidateProperties.FirstOrDefault(x => string.Equals(x.Name, relationName, propertyNameComparison)); if ((matchesOtherCandidateProperty != null) && (matchesOtherCandidateProperty.Type != null) && (matchesOtherCandidateProperty.Type.CodeType != null)) foundRelatedEntityTypes = new[] { matchesOtherCandidateProperty.Type.CodeType }.ToList(); else foundRelatedEntityTypes = projectTypeLocator.FindTypes(project, relationName).Distinct().ToList(); // Get the primary key info for each possible type match so we can check it's a plausible entity. var foundRelatedEntityTypesPlusPrimaryKeyInfo = (from relatedEntityType in foundRelatedEntityTypes select new { type = relatedEntityType, primaryKeys = PrimaryKeyLocation.GetPrimaryKeys(relatedEntityType).ToList() }).ToList(); // It's only a plausible entity if it has a single primary key, so filter out ones that don't, then ensure we're left with an unambiguous match foundRelatedEntityTypesPlusPrimaryKeyInfo.RemoveAll(x => x.primaryKeys.Count != 1); if (foundRelatedEntityTypesPlusPrimaryKeyInfo.Count != 1) return null; return new RelatedEntityInfo(RelationType.Parent, relationName, property, foundRelatedEntityTypesPlusPrimaryKeyInfo.Single().type, foundRelatedEntityTypesPlusPrimaryKeyInfo.Single().primaryKeys.Single().Name, matchesOtherCandidateProperty); }
public IEnumerable<RelatedEntityInfo> GetRelatedEntities(CodeType codeType, Project project, IProjectTypeLocator projectTypeLocator) { var thisEntityPrimaryKeys = PrimaryKeyLocation.GetPrimaryKeys(codeType).ToList(); var propertiesToConsider = (from property in codeType.VisibleMembers().OfType<CodeProperty>() where ((CodeElement)property).IsPublic() && !thisEntityPrimaryKeys.Contains(property) // Exclude its own primary keys, otherwise it will always be related to itself select property).ToList(); foreach (var property in propertiesToConsider) { var relatedEntityInfo = GetRelatedParentEntityInfo(property, propertiesToConsider, project, projectTypeLocator) ?? GetRelatedChildEntityInfo(property, project, projectTypeLocator); if (relatedEntityInfo != null) yield return relatedEntityInfo; } }
private static CodeType ExtractFirstGenericArgOfCollectionType(CodeProperty property, Project project, IProjectTypeLocator projectTypeLocator) { // This is difficult for VB types because the API won't let us know the generic args when scanning the type hierarchy. // We can see if a type implements ICollection<T>, but there's no way to know what T is. So, try to spot some // common collection types at the CodeTypeRef level where VB gives us a string representation of the closed generic type. var genericArg = ExtractFirstGenericArgOfSpecificCollectionType(property.Type, property.Language, typeof (List<>), typeof (IList<>), typeof(Collection<>), typeof (ICollection<>), typeof (EntitySet<>)); // If this failed, then for C# types at least, we can scan up the inheritance hierarchy looking for something that implements ICollection<T> if (string.IsNullOrEmpty(genericArg)) { if (!string.Equals(property.Language, VsConstants.VbCodeModelLanguageGuid, StringComparison.OrdinalIgnoreCase)) genericArg = ExtractFirstGenericArgOfImplementedICollectionInterface(property.Type.CodeType as CodeClass); } // Convert the string representation of the collection element type to a project-local CodeType if (string.IsNullOrEmpty(genericArg)) return null; var foundTypes = projectTypeLocator.FindTypes(project, genericArg).ToList(); if (foundTypes.Count != 1) // Only accept unambiguous match return null; return foundTypes.Single(); }
internal GetPrimaryKeyCmdlet(ISolutionManager solutionManager, IProjectTypeLocator projectTypeLocator) : base(solutionManager, null, null) { _projectTypeLocator = projectTypeLocator; }
private static RelatedEntityInfo GetRelatedParentEntityInfo(CodeProperty property, IEnumerable <CodeProperty> allCandidateProperties, Project project, IProjectTypeLocator projectTypeLocator) { // First, we need to be able to extract "SomeType" from properties called "SomeTypeID" // "SomeType" is the name of the relation, and either corresponds to an entity type, or to another property whose type is an entity if (!property.Name.EndsWith(PropertySuffix, StringComparison.OrdinalIgnoreCase)) { return(null); } var relationName = property.Name.Substring(0, property.Name.Length - PropertySuffix.Length); if (string.IsNullOrEmpty(relationName)) { return(null); } // Next, "SomeType" needs to correspond to plausible entity or be the name of another property whose type is a plausible entity List <CodeType> foundRelatedEntityTypes; var propertyNameComparison = VsConstants.VbCodeModelLanguageGuid.Equals(property.Language, StringComparison.OrdinalIgnoreCase) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; var matchesOtherCandidateProperty = allCandidateProperties.FirstOrDefault(x => string.Equals(x.Name, relationName, propertyNameComparison)); if ((matchesOtherCandidateProperty != null) && (matchesOtherCandidateProperty.Type != null) && (matchesOtherCandidateProperty.Type.CodeType != null)) { foundRelatedEntityTypes = new[] { matchesOtherCandidateProperty.Type.CodeType } }
public IEnumerable <RelatedEntityInfo> GetRelatedEntities(CodeType codeType, Project project, IProjectTypeLocator projectTypeLocator) { var thisEntityPrimaryKeys = PrimaryKeyLocation.GetPrimaryKeys(codeType).ToList(); var propertiesToConsider = (from property in codeType.VisibleMembers().OfType <CodeProperty>() where ((CodeElement)property).IsPublic() && !thisEntityPrimaryKeys.Contains(property) // Exclude its own primary keys, otherwise it will always be related to itself select property).ToList(); foreach (var property in propertiesToConsider) { var relatedEntityInfo = GetRelatedParentEntityInfo(property, propertiesToConsider, project, projectTypeLocator) ?? GetRelatedChildEntityInfo(property, project, projectTypeLocator); if (relatedEntityInfo != null) { yield return(relatedEntityInfo); } } }
private static RelatedEntityInfo GetRelatedChildEntityInfo(CodeProperty property, Project project, IProjectTypeLocator projectTypeLocator) { // We are only interested in properties that implement ICollection<TEntity> var collectionElementType = ExtractFirstGenericArgOfCollectionType(property, project, projectTypeLocator); if (collectionElementType == null) return null; // The element type has to be plausibly an entity, meaning that it has a single primary key var collectionElementTypePrimaryKeys = PrimaryKeyLocation.GetPrimaryKeys(collectionElementType).ToList(); if (collectionElementTypePrimaryKeys.Count != 1) return null; return new RelatedEntityInfo(RelationType.Child, property.Name, property, collectionElementType, collectionElementTypePrimaryKeys.Single().Name, property); }
internal GetRelatedEntitiesCmdlet(ISolutionManager solutionManager, IProjectTypeLocator projectTypeLocator) : base(solutionManager, null, null) { _projectTypeLocator = projectTypeLocator; }
internal GetProjectTypeCmdlet(ISolutionManager solutionManager, IProjectTypeLocator projectTypeLocator) : base(solutionManager, null, null) { _projectTypeLocator = projectTypeLocator; }