private static IEnumerable <ExplorerItem> GetRoutines(Type contextType) { // This looks for stored proc methods on the sub-typed EM. Unlike the EF driver, it does not group the procs into an SP category. // The logic is actually stolen somewhat from the EF driver. // Sprocs currently return nothing (ignored here) or an IEnumerable of entity type, complex type, or nullable scalar primitive. // It's too slow to load metadata to check if entity/complex type, so we instead check for a nullable<t> return type, which indicates a scalar. var procs = ( from mi in contextType.GetMethods() where mi.DeclaringType.FullName != "IdeaBlade.EntityModel.EntityManager" where mi.ReturnType.IsGenericType where typeof(IEnumerable <>).IsAssignableFrom(mi.ReturnType.GetGenericTypeDefinition()) orderby mi.Name let rettype = mi.ReturnType.GetGenericArguments()[0] let scalartype = rettype.IsGenericType && rettype.GetGenericTypeDefinition() == typeof(Nullable <>) select new ExplorerItem(mi.Name, ExplorerItemKind.QueryableObject, ExplorerIcon.StoredProc) { ToolTipText = mi.Name, DragText = mi.Name + "(" + (mi.GetParameters().Any <ParameterInfo>() ? "..." : "") + ")", Children = // Get parms (from param in mi.GetParameters() select new ExplorerItem(param.Name + " (" + DataContextDriver.FormatTypeName(param.ParameterType, false) + ")", ExplorerItemKind.Parameter, ExplorerIcon.Parameter) ) // And regular properties (if a complex or entity type) .Union (from col in rettype.GetProperties(BindingFlags.Instance | BindingFlags.Public) where scalartype == false where !EntityMemberProvider.IsAspect(col) select new ExplorerItem(col.Name, ExplorerItemKind.Property, ExplorerIcon.Column) ) // And a really screwy way to include a scalar return property. .Union (from t in new[] { rettype } where scalartype == true select new ExplorerItem(DataContextDriver.FormatTypeName(t, false), ExplorerItemKind.Property, ExplorerIcon.Column) ) .ToList() }).ToList(); return(procs); }
public static List <ExplorerItem> GetSchema(IConnectionInfo cxInfo, Type customType) { // Return the objects with which to populate the Schema Explorer by reflecting over customType. // We'll start by retrieving all the properties of the custom type that implement IEnumerable<T>: var topLevelProps = ( from prop in customType.GetProperties() where prop.PropertyType != typeof(string) // Display all properties of type IEnumerable<T> (except for string!) let ienumerableOfT = prop.PropertyType.GetInterface("System.Collections.Generic.IEnumerable`1") where ienumerableOfT != null orderby prop.Name select new ExplorerItem(prop.Name, ExplorerItemKind.QueryableObject, ExplorerIcon.Table) { IsEnumerable = true, ToolTipText = DataContextDriver.FormatTypeName(prop.PropertyType, false), // Store the entity type to the Tag property. We'll use it later. Tag = ienumerableOfT.GetGenericArguments()[0] } ).ToList(); // Create a lookup keying each element type to the properties of that type. This will allow // us to build hyperlink targets allowing the user to click between associations: var elementTypeLookup = topLevelProps.ToLookup(tp => (Type)tp.Tag); // Populate the columns (properties) of each entity: foreach (ExplorerItem table in topLevelProps) { table.Children = ((Type)table.Tag) .GetProperties() .Select(childProp => GetChildItem(elementTypeLookup, childProp)) .OrderBy(childItem => childItem.Kind) .ToList(); } return(topLevelProps); }
private static ExplorerItem GetChildItem(ILookup <Type, ExplorerItem> elementTypeLookup, PropertyInfo childProp) { // If the property's type is in our list of entities, then it's a Many:1 (or 1:1) reference. // We'll assume it's a Many:1 (we can't reliably identify 1:1s purely from reflection). if (elementTypeLookup.Contains(childProp.PropertyType)) { return new ExplorerItem(childProp.Name, ExplorerItemKind.ReferenceLink, ExplorerIcon.ManyToOne) { HyperlinkTarget = elementTypeLookup[childProp.PropertyType].First(), // FormatTypeName is a helper method that returns a nicely formatted type name. ToolTipText = DataContextDriver.FormatTypeName(childProp.PropertyType, true) } } ; // Is the property's type a collection of entities? Type ienumerableOfT = childProp.PropertyType.GetInterface("System.Collections.Generic.IEnumerable`1"); if (ienumerableOfT != null) { Type elementType = ienumerableOfT.GetGenericArguments()[0]; if (elementTypeLookup.Contains(elementType)) { return new ExplorerItem(childProp.Name, ExplorerItemKind.CollectionLink, ExplorerIcon.OneToMany) { HyperlinkTarget = elementTypeLookup[elementType].First(), ToolTipText = DataContextDriver.FormatTypeName(elementType, true) } } ; } // Ordinary property: var isKey = childProp.GetCustomAttributes(false).Any(a => a.GetType().Name == "KeyAttribute"); return(new ExplorerItem(childProp.Name + " (" + DataContextDriver.FormatTypeName(childProp.PropertyType, false) + ")", ExplorerItemKind.Property, isKey ? ExplorerIcon.Key : ExplorerIcon.Column) { DragText = childProp.Name }); }
/// <summary> /// Generate Schema information. /// </summary> /// <param name="cxInfo">IConnectionInfo</param> /// <param name="customType">Context Type</param> /// <returns>Schema Information.</returns> public override List <ExplorerItem> GetSchema(IConnectionInfo cxInfo, Type customType) { // Instantiate CrmProperties. CrmProperties props = new CrmProperties(cxInfo); // Instantiate ExplorerItem list. List <ExplorerItem> schema = new List <ExplorerItem>(); // Create Tables for Schema. foreach (PropertyInfo prop in customType.GetRuntimeProperties()) { // If property is not Generic Type or IQueryable, then ignore. if (!prop.PropertyType.IsGenericType || prop.PropertyType.Name != "DataServiceQuery`1") { continue; } // Create ExploreItem with Table icon as this is top level item. ExplorerItem item = new ExplorerItem(prop.Name, ExplorerItemKind.QueryableObject, ExplorerIcon.Table) { // Store Entity Type to Tag. Tag = prop.PropertyType.GenericTypeArguments[0].Name, IsEnumerable = true, Children = new List <ExplorerItem>() }; schema.Add(item); } schema = schema.OrderBy(x => x.Text).ToList <ExplorerItem>(); // Then create columns for each table. Loop through tables again. foreach (PropertyInfo prop in customType.GetRuntimeProperties()) { // Obtain Table item from table lists. var item = schema.Where(x => x.Text == prop.Name).FirstOrDefault(); if (item == null) { continue; } // Get all property from Entity for the table. (i.e. Account for AccountSet) foreach (PropertyInfo childprop in customType.Module.GetTypes().Where(x => x.Name == prop.PropertyType.GenericTypeArguments[0].Name).First().GetRuntimeProperties()) { // If property is IEnumerable type, then it is 1:N or N:N relationship field. // Need to find a way to figure out if this is 1:N or N:N. At the moment, I just make them as OneToMany type. if (childprop.PropertyType.IsGenericType && childprop.PropertyType.Name == "IEnumerable`1") { // Try to get LinkTarget. ExplorerItem linkTarget = schema.Where(x => x.Tag.ToString() == childprop.PropertyType.GetGenericArguments()[0].Name).FirstOrDefault(); if (linkTarget == null) { continue; } // Create ExplorerItem as Colleciton Link. item.Children.Add( new ExplorerItem( childprop.Name, ExplorerItemKind.CollectionLink, ExplorerIcon.OneToMany) { HyperlinkTarget = linkTarget, ToolTipText = DataContextDriver.FormatTypeName(childprop.PropertyType, false) }); } else { // Try to get LinkTarget to check if this field is N:1. ExplorerItem linkTarget = schema.Where(x => x.Tag.ToString() == childprop.PropertyType.Name).FirstOrDefault(); // If no linkTarget exists, then this is normal field. if (linkTarget == null) { // Create ExplorerItem as Column. item.Children.Add( new ExplorerItem( childprop.Name + " (" + DataContextDriver.FormatTypeName(childprop.PropertyType, false) + ")", ExplorerItemKind.Property, ExplorerIcon.Column) { ToolTipText = DataContextDriver.FormatTypeName(childprop.PropertyType, false) }); } else { // Otherwise, create ExploreItem as N:1 item.Children.Add( new ExplorerItem( childprop.Name + " (" + DataContextDriver.FormatTypeName(childprop.PropertyType, false) + ")", ExplorerItemKind.ReferenceLink, ExplorerIcon.ManyToOne) { HyperlinkTarget = linkTarget, ToolTipText = DataContextDriver.FormatTypeName(childprop.PropertyType, false) }); } } // Order Fields item.Children = item.Children.OrderBy(x => x.Text).ToList <ExplorerItem>(); } } // Order Entities. schema = schema.OrderBy(x => x.Text).ToList <ExplorerItem>(); return(schema); }