protected void DefineForeignKeyNodes(string childForeignKeyPrefix, string childForeignKeyName, CodeProperty masterCodeProp, IList <PropertySelectorViewModel> list, string detailClassName, int currentNestedLevel) { CodeClass masterCodeClass = masterCodeProp.Type.CodeType as CodeClass; string masterCodePropName = masterCodeProp.Name; List <SolutionCodeElement> primKeyProps = GetPrimaryKeyProperties(masterCodeClass); // SolutionCodeElement.CodeElementRef holds 'CodeProperty' // collect ColumnAttributes to define order if (primKeyProps.Count < 1) { // throw an exception here return; } ////////////////////////////////////////////////// /// The 1st case: /// --------- /// public class DetailType { /// /// public int MasterRefId1 { get; set; } /// public int MasterRefId2 { get; set; } /// /// [ForeignKey("MasterRefId1")] /// [ForeignKey("MasterRefId2")] /// public MasterType MasterProp { get; set; } /// } ////////////////////////////////////////////////// foreach (CodeElement cea in masterCodeProp.Attributes) { string foreignKeyName = ""; CodeAttribute ca = cea as CodeAttribute; if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute")) { foreach (CodeElement chld in ca.Children) { if (chld is CodeAttributeArgument) { foreignKeyName = (chld as CodeAttributeArgument).Value; } foreignKeyName = foreignKeyName.Replace("\"", ""); } foreach (ClassFiledSelectorViewModel itm in list) { if (foreignKeyName.Equals(itm.OriginalPropertyName)) { PropertySelectorViewModel fk = null; if (itm.ForeigKeyParentProperties == null) { itm.ForeigKeyParentProperties = new ObservableCollection <PropertySelectorViewModel>(); } else { fk = itm.ForeigKeyPPByForeignKN(masterCodePropName); } if (fk == null) { fk = new PropertySelectorViewModel() { ForeignKeyName = masterCodePropName }; itm.IsForeignKeyField = true; itm.ForeigKeyParentProperties.Add(fk); } } } } } ////////////////////////////////////////////////// /// The 2nd case: /// --------- /// public class DetailType { /// /// public int MasterRefId1 { get; set; } /// public int MasterRefId2 { get; set; } /// } /// public class MasterType { /// [ForeignKey("MasterRefId1")] /// [ForeignKey("MasterRefId2")] /// public ICollection<DetailType> DetailProps { get; set; } /// } ////////////////////////////////////////////////// if (!string.IsNullOrEmpty(detailClassName)) { foreach (CodeElement ce in masterCodeClass.Members) { if (ce.Kind != vsCMElement.vsCMElementProperty) { continue; } CodeProperty loopCodeProp = ce as CodeProperty; if (loopCodeProp.Access != vsCMAccess.vsCMAccessPublic) { continue; } if (loopCodeProp.Type == null) { continue; } if (loopCodeProp.Type.CodeType == null) { continue; } bool isNotMapped = false; foreach (CodeElement cea in loopCodeProp.Attributes) { CodeAttribute ca = cea as CodeAttribute; if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute")) { isNotMapped = true; break; } } if (isNotMapped) { continue; } CodeTypeRef ctRef = loopCodeProp.Type; if (ctRef.TypeKind == vsCMTypeRef.vsCMTypeRefArray) { continue; } if (ctRef.TypeKind != vsCMTypeRef.vsCMTypeRefCodeType) { continue; } if (ctRef.CodeType.Kind != vsCMElement.vsCMElementInterface) { continue; } string className = ctRef.CodeType.FullName.Replace("System.Collections.Generic.ICollection<", "").Replace(">", "").Trim(); if (!detailClassName.Equals(className, StringComparison.OrdinalIgnoreCase)) { continue; } // look for InversePropertyAttribute string inversePropertyName = ""; foreach (CodeElement cea in loopCodeProp.Attributes) { CodeAttribute ca = cea as CodeAttribute; if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.InversePropertyAttribute")) { foreach (CodeElement chld in ca.Children) { if (chld is CodeAttributeArgument) { inversePropertyName = (chld as CodeAttributeArgument).Value; } inversePropertyName = inversePropertyName.Replace("\"", ""); } } } if (!string.IsNullOrEmpty(inversePropertyName)) { if (!inversePropertyName.Equals(masterCodePropName, StringComparison.OrdinalIgnoreCase)) { continue; } } foreach (CodeElement cea in loopCodeProp.Attributes) { string foreignKeyName = ""; CodeAttribute ca = cea as CodeAttribute; if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute")) { foreach (CodeElement chld in ca.Children) { if (chld is CodeAttributeArgument) { foreignKeyName = (chld as CodeAttributeArgument).Value; } foreignKeyName = foreignKeyName.Replace("\"", ""); } foreach (ClassFiledSelectorViewModel itm in list) { if (foreignKeyName.Equals(itm.OriginalPropertyName)) { PropertySelectorViewModel fk = null; if (itm.ForeigKeyParentProperties == null) { itm.ForeigKeyParentProperties = new ObservableCollection <PropertySelectorViewModel>(); } else { fk = itm.ForeigKeyPPByForeignKN(masterCodePropName); } if (fk == null) { fk = new PropertySelectorViewModel() { ForeignKeyName = masterCodePropName }; itm.ForeigKeyParentProperties.Add(fk); itm.IsForeignKeyField = true; } } } } } } } string[] names = masterCodeProp.Type.AsFullName.Split(new char[] { '.' }); string masterTypeName = names[names.Length - 1]; //masterCodePropName foreach (SolutionCodeElement primKeyProp in primKeyProps) { string primKeyPropName = primKeyProp.CodeElementName; if ("Id".Equals(primKeyPropName, StringComparison.OrdinalIgnoreCase)) { primKeyPropName = masterTypeName + primKeyPropName; } string fkNm = masterCodePropName + primKeyPropName; if (DefineForeigKeyNodeByForeigKeyFiledName(list, fkNm, masterCodePropName)) { continue; } fkNm = masterTypeName + primKeyPropName; if (DefineForeigKeyNodeByForeigKeyFiledName(list, fkNm, masterCodePropName)) { continue; } DefineForeigKeyNodeByForeigKeyFiledName(list, primKeyPropName, masterCodePropName); } // collect all foreign key fields for the given navigation property: masterCodePropName List <ClassFiledSelectorViewModel> fcflds = new List <ClassFiledSelectorViewModel>(); foreach (ClassFiledSelectorViewModel itm in list) { if (itm.ForeigKeyParentProperties == null) { continue; } if (itm.ForeigKeyPPByForeignKN(masterCodePropName) == null) { continue; } fcflds.Add(itm); } if (fcflds.Count > 1) { fcflds.Sort((x, y) => x.FieldOrder - y.FieldOrder); } if (primKeyProps.Count > 1) { foreach (SolutionCodeElement sce in primKeyProps) { CodeProperty cp = sce.CodeElementRef as CodeProperty; foreach (CodeElement cea in cp.Attributes) { bool OrderIsFound = false; CodeAttribute ca = cea as CodeAttribute; if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.ColumnAttribute")) { foreach (CodeElement chld in ca.Children) { if ("Order".Equals(chld.Name, System.StringComparison.OrdinalIgnoreCase)) { if (chld is CodeAttributeArgument) { int val; if (int.TryParse((chld as CodeAttributeArgument).Value, out val)) { sce.Order = val; OrderIsFound = true; break; } } } } } if (OrderIsFound) { break; } } } primKeyProps.Sort((x, y) => x.Order - y.Order); } int Count = primKeyProps.Count; if (Count > fcflds.Count) { Count = fcflds.Count; } for (int i = 0; i < Count; i++) { ClassFiledSelectorViewModel cfsvm = fcflds[i]; PropertySelectorViewModel psvm = cfsvm.ForeigKeyPPByForeignKN(masterCodePropName); psvm.OriginalPropertyName = primKeyProps[i].CodeElementName; CodeProperty cp = primKeyProps[i].CodeElementRef as CodeProperty; psvm.TypeFullName = cp.Type.AsFullName; psvm.UnderlyingTypeName = cp.Type.AsFullName; psvm.TypeIsNullable = false; psvm.PocoName = masterCodeClass.Name; psvm.PocoFullName = masterCodeClass.FullName; if (currentNestedLevel + 1 <= this.MaxNestedLevel) { psvm.ForeigKeyParentProperties = new ObservableCollection <PropertySelectorViewModel>(); DoPrepareClassFiledSelectorData(psvm.ChildForeignKeyPrefix, psvm.ForeignKeyName, psvm.ForeigKeyParentProperties, masterCodeClass as CodeElement, primKeyProps, currentNestedLevel); } } }
protected void DoPrepareClassFiledSelectorData(string childForeignKeyPrefix, string childForeignKeyName, ObservableCollection <PropertySelectorViewModel> fkpp, CodeElement currentCodeElement, List <SolutionCodeElement> primKeyProps, int currentNestedLevel) { currentNestedLevel++; if (this.MaxNestedLevel < currentNestedLevel) { return; } if (fkpp == null) { return; } if (fkpp.Count > 0) { return; } if (currentCodeElement.Kind != vsCMElement.vsCMElementClass) { return; } CodeClass currentCodeClass = currentCodeElement as CodeClass; if (primKeyProps == null) { primKeyProps = GetPrimaryKeyProperties(currentCodeClass); } if (primKeyProps.Count < 1) { // throw an exception here return; } IList <CodeProperty> navigationProps = new List <CodeProperty>(); IList <String> fkeys = new List <String>(); int columnOrder = 0; foreach (CodeElement ce in currentCodeClass.Members) { fkeys.Clear(); bool isNotMapped = false; //bool keyAttrib = false; bool hasForeignAttrib = false; string foreignKeyName = ""; bool inversePropertyAttribute = false; bool requiredAttribute = false; // bool columnAttribute = false; int columnAttributeOrder = -1; String typeName = ""; bool typeIsNullable = false; if (ce.Kind != vsCMElement.vsCMElementProperty) { continue; } CodeProperty cp = ce as CodeProperty; if (cp.Access != vsCMAccess.vsCMAccessPublic) { continue; } if (cp.Type == null) { continue; } if (cp.Type.CodeType == null) { continue; } foreach (CodeElement cea in cp.Attributes) { CodeAttribute ca = cea as CodeAttribute; if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute")) { isNotMapped = true; } //if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.KeyAttribute")) //{ // keyAttrib = true; //} if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute")) { hasForeignAttrib = true; foreach (CodeElement chld in ca.Children) { if (chld is CodeAttributeArgument) { foreignKeyName = (chld as CodeAttributeArgument).Value; } foreignKeyName = foreignKeyName.Replace("\"", ""); if (!string.IsNullOrEmpty(foreignKeyName)) { if (!fkeys.Contains(foreignKeyName)) { fkeys.Add(foreignKeyName); } } } } if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.InversePropertyAttribute")) { inversePropertyAttribute = true; } if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.RequiredAttribute")) { requiredAttribute = true; } if (ca.FullName.Contains("System.ComponentModel.DataAnnotations.Schema.ColumnAttribute")) { // columnAttribute = true; foreach (CodeElement chld in ca.Children) { if ("Order".Equals(chld.Name, System.StringComparison.OrdinalIgnoreCase)) { if (chld is CodeAttributeArgument) { int val; if (int.TryParse((chld as CodeAttributeArgument).Value, out val)) { columnAttributeOrder = val; } } } } } } if (inversePropertyAttribute || isNotMapped) { continue; } CodeTypeRef ctf = cp.Type; // if CodeTypeRef.TypeKind = vsCMTypeRef.vsCMTypeRefArray the 'CodeTypeRef.ElementType' holds the type of the array Item // but in our case we will ignory Arrays if (ctf.TypeKind == vsCMTypeRef.vsCMTypeRefArray) { continue; } if (ctf.TypeKind == vsCMTypeRef.vsCMTypeRefCodeType) { // this is ForeignKey-navigation property so it must be saved for a while if (cp.Type.CodeType.Kind == vsCMElement.vsCMElementClass) { navigationProps.Add(cp); continue; } // ICollection<T> property: this is InverseProperty(...) so it must be ignored if (cp.Type.CodeType.Kind == vsCMElement.vsCMElementInterface) { string fl = cp.Type.CodeType.FullName; if (fl != null) { fl = ""; } continue; } if (!ctf.AsFullName.StartsWith("System.Nullable")) { continue; } typeName = ctf.AsFullName.Replace("System.Nullable", "").Replace("<", "").Replace(">", "").Trim(); typeIsNullable = true; } else { typeName = ctf.AsFullName; } if (columnAttributeOrder < 0) { columnAttributeOrder = columnOrder; } ClassFiledSelectorViewModel aProperty = new ClassFiledSelectorViewModel() { OriginalPropertyName = cp.Name, ViewModelFieldName = childForeignKeyPrefix + childForeignKeyName + cp.Name, JsonPropertyFieldName = childForeignKeyPrefix + childForeignKeyName + cp.Name, FieldOrder = columnAttributeOrder, IsForeignKeyField = hasForeignAttrib, ForeignKeyName = childForeignKeyName, ForeignKeyAlias = childForeignKeyName, ChildForeignKeyPrefix = childForeignKeyPrefix, TypeFullName = ctf.AsFullName, UnderlyingTypeName = typeName, TypeIsNullable = typeIsNullable, UpdateDependent = true, UpdateNested = true, PocoName = currentCodeClass.Name, PocoFullName = currentCodeClass.FullName, HasRequiredAttribute = requiredAttribute }; if (hasForeignAttrib) { foreach (string fk in fkeys) { if (aProperty.ForeigKeyParentProperties == null) { aProperty.ForeigKeyParentProperties = new ObservableCollection <PropertySelectorViewModel>(); } PropertySelectorViewModel fko = new PropertySelectorViewModel() { ForeignKeyName = fk, ChildForeignKeyPrefix = childForeignKeyPrefix + childForeignKeyName, ForeignKeyAlias = fk, UpdateDependent = true, UpdateNested = true, }; aProperty.ForeigKeyParentProperties.Add(fko); } } fkpp.Add(aProperty); columnOrder++; } foreach (SolutionCodeElement cp in primKeyProps) { string propNmae = cp.CodeElementName; foreach (ClassFiledSelectorViewModel itm in fkpp) { if (propNmae.Equals(itm.OriginalPropertyName, StringComparison.OrdinalIgnoreCase)) { itm.IsKeyField = true; break; } } } foreach (CodeProperty cp in navigationProps) { DefineForeignKeyNodes(childForeignKeyPrefix, childForeignKeyName, cp, fkpp, currentCodeClass.Name, currentNestedLevel); } OnPropertyChanged("ForeigKeyParentProperties"); }