/// <summary> /// Adds every publicly-settable field or property of the root entity to the select list, removing any beginning underscore from the name of the selected column. /// </summary> /// <returns> /// This RootQueryBuilder object. /// </returns> public RootQueryBuilder <T> Select(IEnumerable <Expression <Func <T, object> > > getterExprs) { // 1. Cache all setters for type T. IDictionary <string, SetValue> setters = CachedTypeData.FetchSettersOf <T>(); // 2. Add "RootTable"."propOrFieldName" to the select list or just "propOrFieldName" if table_alias is null for every // field and property returned in getterExprs foreach (Expression <Func <T, object> > getterExpr in getterExprs) { string propOrFieldName = ExpressionTreeHelper.GetPropOrFieldNameFromLambdaExpr <T>(getterExpr); // Only if there is a public setter for this property or if the field is public if (setters.ContainsKey(propOrFieldName) == false) { continue; } // Remove a possible underscore before adding it to selection if (propOrFieldName[0] == '_') { propOrFieldName = propOrFieldName.Substring(1); } string select_projection = RootTable + "." + propOrFieldName; Qb.Select(select_projection); } return(this); }
/// <summary> /// Adds every publicly-settable field or property in type <typeref name="T"/> to the select list, removing any leading underscore from the name of the selected column. /// </summary> /// <returns> /// This RootQueryBuilder object. /// </returns> public RootQueryBuilder <T> SelectAllColumns() { // 1. Go after all the public settable properties and public fields in type T IDictionary <string, SetValue> setters = CachedTypeData.FetchSettersOf <T>(); // 2. Add all of them to the select list! foreach (string propOrField in setters.Select(x => x.Key)) { string selectableName = propOrField; if (selectableName[0] == '_') { selectableName = propOrField.Substring(1); } // Just to have pretty SQL when there is only one table queried if (QueriedTables.Count == 1) { Qb.Select(selectableName); } else { Qb.Select(RootTable + "." + selectableName); } } return(this); }
/// <summary> /// Execute the query and enumerates the results of type <typeparamref name="T"/>. This method DOES NOT avoid duplicates /// of the root entity from being returned if there is any join to a one-to-many relationed entity. Do not make this public, /// since enumerating results one by one will interfere with one-to-many fetching (by not having all elements of the collection /// for some yielded results). /// </summary> /// <param name='com'> /// The IDbCommand to be executed. /// </param> /// <typeparam name='T'> /// The type of each result. /// </typeparam> private IEnumerable <T> AsEnumerable(IDbCommand com) { // Get the fields and properties of type T and put their setter and getter methods in the cache, if not already there IDictionary <string, SetValue> rootEntitySetters = CachedTypeData.FetchSettersOf <T>(); // To update collections of all returned root entities in one-to-many relations, we keep them here for easy access IDictionary <T, IDictionary <string, IList> > rootEntitiesAndAssociatedCollections = null; bool hasSomeFetchManyAssociation = FetchManyFetchers != null; if (hasSomeFetchManyAssociation) { rootEntitiesAndAssociatedCollections = new Dictionary <T, IDictionary <string, IList> >(); } using (IDataReader dr = com.ExecuteReader()) { while (dr.Read()) { T temp = new T(); // Set the fields/properties of the root object accordingly, skipping collections at first MemberSetter.SetNonCollectionMembersOf(temp, RootEntityProjectionsMap, dr); if (hasSomeFetchManyAssociation) { if (rootEntitiesAndAssociatedCollections.ContainsKey(temp) == false) { rootEntitiesAndAssociatedCollections.Add(temp, new Dictionary <string, IList>()); } foreach (var collectionMemberFetcher in FetchManyFetchers) { string memberName = collectionMemberFetcher.Key; SetValue setter = rootEntitySetters[memberName]; ICollectionResultsFetcher <T> collectionFetcher = collectionMemberFetcher.Value; IDictionary <string, IList> collectionsPerMemberName = rootEntitiesAndAssociatedCollections[temp]; IList collection; if (collectionsPerMemberName.ContainsKey(memberName)) { collection = collectionsPerMemberName[memberName]; setter(temp, collection); } else { collectionFetcher.CreateCollectionAndAssignToMember(temp, setter, out collection); collectionsPerMemberName.Add(memberName, collection); } // Now add an element to the collection and set its properties collectionFetcher.AddElementToCollection(dr, collection); } } yield return(temp); } } }
/// <summary> /// Adds every publicly-settable field or property in type <typeref name="T"/> to the select list, removing any leading underscore from the name of the selected column. /// </summary> /// <returns> /// This QueryBuilder object. /// </returns> /// <typeparam name='T'> /// The class with the properties to be selected. /// </typeparam> public QueryBuilder AddColumnsOf <T>() { // 1. Go after all the public settable properties and public fields in type T IDictionary <string, SetValue> setters = CachedTypeData.FetchSettersOf <T>(); // 2. Add all of them to the select list! foreach (string propOrField in setters.Select(x => x.Key)) { string selectableName = propOrField; if (selectableName[0] == '_') { selectableName = propOrField.Substring(1); } Select(selectableName); } return(this); }
/// <summary> /// Goes through the list of projections in the SELECT clause and removes the projections whose /// names are not similar to any of the names of T's public fields and properties. /// It also aliases similar names correctly, putting an underscore if the property/field starts with an underscore. /// </summary> /// <typeparam name='T'> /// The type whose properties are to be aliased and fetched. /// </typeparam> public QueryBuilder RemoveSelectionsNotOf <T>() { IDictionary <string, SetValue> setters = CachedTypeData.FetchSettersOf <T>(); IList <ProjectionFragment> newSelects = new List <ProjectionFragment>(); foreach (ProjectionFragment proj in selectedProjections) { string fqn = proj.GetName(); // If the projection's name is not a property name, then.. if (!setters.ContainsKey(fqn)) { // 1. The property might begin with an underscore, check for that and alias the projection correctly if (setters.ContainsKey("_" + fqn)) { proj.As("_" + fqn); newSelects.Add(proj); //Console.WriteLine("- Found {0}", proj.GetName()); } // 2. The property does not begin with an underscore, don't add it to the new list (do nothing) else { //Console.WriteLine("- Couldn't find a property or field named {0} or _{0} with a public setter", fqn); } } // If it is a property name, it must be included in the new select list! else { newSelects.Add(proj); //Console.WriteLine("Found {0}", proj.GetName()); } } // Renews the select list selectedProjections = newSelects; return(this); }
/// <summary> /// Sets the non collection members of <paramref name="obj"/> as long as they are present in <paramref name="columnsNames"/>. /// </summary> /// <param name="obj">The object whose fields and properties will be set.</param> /// <param name="initialColumnIdx">The zero-starting index of the first column in <paramref name="columnsNames"/>.</param> /// <param name="columnsNames">A mapping of the queried projections to <paramref name="obj"/>'s members' names.</param> /// <param name="dr">The IDataReader from which columns' values will be retrieved.</param> public static void SetNonCollectionMembersOf <T>(T obj, IDictionary <string, string> columnsNames, IDataReader dr) { var setters = CachedTypeData.FetchSettersOf <T>(); foreach (KeyValuePair <string, string> projectionAndMember in columnsNames) { string memberName = projectionAndMember.Value; string projectionName = projectionAndMember.Key; SetValue setter; try { setter = setters[memberName]; } catch (KeyNotFoundException) { // Just skip for now.. Assume this column is not in this object but may be in another continue; //throw new InvalidOperationException("Object of class " + typeof(T2) + " does not possess a publicly settable member named \"" + memberName + "\""); } // Special case of collection. Skip! MemberInfo memberInfo = CachedTypeData.GetMemberInfo <T>(memberName); if (TypeUtils.IsGenericList(memberInfo.GetUnderlyingType())) { continue; } // Check for nulls int columnIdx = dr.GetOrdinal(projectionName); if (dr.IsDBNull(columnIdx)) { setter(obj, null); } else { setter(obj, dr.GetValue(columnIdx)); } } }