/// <summary> /// Gets the expression with overrides. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="serviceInstance">The service instance.</param> /// <param name="parameterExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="selection">A formatted string representing the filter settings: FieldName, <see cref="ComparisonType">Comparison Type</see>, (optional) Comparison Value(s)</param> /// <returns></returns> /// <exception cref="System.Exception">Filter issue(s): " + errorMessages.AsDelimited( "; " )</exception> public Expression GetExpressionWithOverrides(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, DataViewFilterOverrides dataViewFilterOverrides, string selection) { var selectionConfig = SelectionConfig.Parse(selection); var dataView = this.GetSelectedDataView(selectionConfig); if (dataView == null) { if (selectionConfig.DataViewId.HasValue && selectionConfig.DataViewId > 0) { // if there is DataViewId but it isn't in the database, the DataView might have been deleted. If so, this could return unexpected results. throw new RockDataViewFilterExpressionException($"DataViewFilter unable to determine DataView for DataViewId {selectionConfig.DataViewId}"); } } if (dataView != null && dataView.DataViewFilter != null) { // Verify that there is not a child filter that uses this view (would result in stack-overflow error) if (DataViewService.IsViewInFilter(dataView, dataView.DataViewFilter)) { throw new System.Exception($"The {dataView.Name} data view references itself recursively within the {this.FormatSelection( entityType, selection ) } data filter."); } if (selectionConfig.UsePersisted == false) { dataViewFilterOverrides?.IgnoreDataViewPersistedValues.Add(dataView.Id); } Expression expression = dataView.GetExpression(serviceInstance, parameterExpression, dataViewFilterOverrides); return(expression); } return(null); }
/// <summary> /// Retrieves and validates a DataView for use in a Filter of another Data View. /// </summary> /// <param name="dataViewGuid"></param> /// <param name="context"></param> /// <returns></returns> public static DataView GetDataViewForFilterComponent(Guid?dataViewGuid, RockContext context = null) { if (!dataViewGuid.HasValue) { return(null); } context = context ?? new RockContext(); var dsService = new DataViewService(context); DataView dataView = dsService.Get(dataViewGuid.Value); if (dataView == null || dataView.DataViewFilter == null) { return(null); } // Verify that the Data View does not contain any references to itself in any of its components. // This configuration would cause a circular reference excpetion during evaluation of the Data View. if (dsService.IsViewInFilter(dataView.Id, dataView.DataViewFilter)) { throw new Exception("Filter issue(s): One of the filters contains a circular reference to the Data View itself."); } return(dataView); }
/// <summary> /// Get the people's Ids inside a DataView filter. /// </summary> /// <param name="dataViewId">The data view identifier.</param> /// <param name="rockContext">The rock context.</param> /// <returns>Returns a directory of people IDs that result from applying the DataView filter</returns> public Dictionary <int, int> DataViewPeopleDirectory(int dataViewId, RockContext rockContext) { var dataViewService = new DataViewService(rockContext); var dataView = dataViewService.GetNoTracking(dataViewId); // Verify that there is not a child filter that uses this view (would result in stack-overflow error) if (dataViewService.IsViewInFilter(dataView.Id, dataView.DataViewFilter)) { throw new Exception("Data View Filter issue(s): One of the filters contains a circular reference to the Data View itself."); } // Evaluate the Data View that defines the candidate population. List <string> errorMessages; var personService = new PersonService(rockContext); var personQuery = personService.Queryable().AsNoTracking(); var paramExpression = personService.ParameterExpression; var whereExpression = dataView.GetExpression(personService, paramExpression, out errorMessages); if (errorMessages.Any()) { throw new Exception("Data View Filter issue(s): " + errorMessages.AsDelimited("; ")); } return(personQuery.Where(paramExpression, whereExpression, null).Select(p => p.Id).ToDictionary(p => p, p => p)); }
/// <summary> /// Gets the expression. /// </summary> /// <param name="context">The context.</param> /// <param name="entityIdProperty">The entity identifier property.</param> /// <param name="selection">The selection.</param> /// <returns></returns> /// <exception cref="System.Exception"> /// Filter issue(s): One of the filters contains a circular reference to the Data View itself. /// or /// Filter issue(s): + errorMessages.AsDelimited( ; ) /// </exception> public override Expression GetExpression(RockContext context, MemberExpression entityIdProperty, string selection) { var settings = new ParticipationRateSelectSettings(selection); if (!settings.IsValid()) { return(this.GetDefaultSelectExpression(context, entityIdProperty)); } // Get the Person Data View that defines the set of candidates from which matching Group Members can be selected. DataView dataView = null; if (settings.DataViewGuid.HasValue) { var dsService = new DataViewService(context); dataView = dsService.Get(settings.DataViewGuid.Value); // Verify that there is not a child filter that uses this view (would result in stack-overflow error) if (dsService.IsViewInFilter(dataView.Id, dataView.DataViewFilter)) { throw new Exception("Filter issue(s): One of the filters contains a circular reference to the Data View itself."); } } if (dataView == null || dataView.DataViewFilter == null) { return(this.GetDefaultSelectExpression(context, entityIdProperty)); } // Evaluate the Data View that defines the candidate population. List <string> errorMessages; var personService = new PersonService(context); var personQuery = personService.Queryable(); var paramExpression = personService.ParameterExpression; var whereExpression = dataView.GetExpression(personService, paramExpression, out errorMessages); if (errorMessages.Any()) { throw new Exception("Filter issue(s): " + errorMessages.AsDelimited("; ")); } personQuery = personQuery.Where(paramExpression, whereExpression, null); var populationIds = personQuery.Select(x => x.Id); // Construct the Query to return the measure of matches for each Group. IQueryable <decimal> resultQuery; switch (settings.MeasureType) { case MeasureTypeSpecifier.ParticipationRateOfGroup: { // Percentage of Group Members that are also in the candidate population. resultQuery = new GroupService(context).Queryable() .Select(p => (p.Members.Count == 0) ? 0 : ((decimal)p.Members.Count(a => (populationIds.Contains(a.PersonId))) / (decimal)p.Members.Count) * 100); } break; case MeasureTypeSpecifier.ParticipationRateOfCandidates: { // Percentage of candidate population that are also Group Members. decimal populationCount = populationIds.Count(); resultQuery = new GroupService(context).Queryable() .Select(p => (p.Members.Count == 0) ? 0 : ((decimal)p.Members.Count(a => (populationIds.Contains(a.PersonId))) / populationCount) * 100); } break; case MeasureTypeSpecifier.NumberOfParticipants: default: { // Number resultQuery = new GroupService(context).Queryable() .Select(p => (decimal)p.Members.Count(a => populationIds.Contains(a.PersonId))); } break; } var selectExpression = SelectExpressionExtractor.Extract(resultQuery, entityIdProperty, "p"); return(selectExpression); }
public override Expression GetExpression(RockContext context, MemberExpression entityIdProperty, string selection) { var settings = new FilterSettings(selection); // // 1. Define Candidate Locations // bool useDefaultLocationsFilter = true; // Get the Location Data View that defines the set of candidates from which proximate Locations can be selected. DataView dataView = null; if (settings.DataViewGuid.HasValue) { var dsService = new DataViewService(context); dataView = dsService.Get(settings.DataViewGuid.Value); if (dataView != null) { if (dataView.DataViewFilter == null) { dataView = null; } else { // Verify that the Group Data View does not contain any references to this Data View in any of its components. if (dsService.IsViewInFilter(dataView.Id, dataView.DataViewFilter)) { throw new Exception("Filter issue(s): One of the filters contains a circular reference to the Data View itself."); } } } } // Evaluate the Data View that defines the candidate Locations. var locationService = new LocationService(context); var locationQuery = locationService.Queryable(); if (dataView != null) { var paramExpression = locationService.ParameterExpression; List <string> errorMessages; var whereExpression = dataView.GetExpression(locationService, paramExpression, out errorMessages); if (errorMessages.Any()) { throw new Exception("Filter issue(s): " + errorMessages.AsDelimited("; ")); } locationQuery = locationQuery.Where(paramExpression, whereExpression, null); useDefaultLocationsFilter = false; // Include child groups? //if (true) //{ // var searchGroupKeys = new HashSet<int>(); // var parentGroups = groupQuery.Select(x => x.Id); // foreach (var parentGroupId in parentGroups) // { // var branchKeys = this.GetGroupBranchKeys(groupService, parentGroupId); // searchGroupKeys.UnionWith(branchKeys); // } // groupQuery = groupService.Queryable().Where(x => searchGroupKeys.Contains(x.Id)); //} } if (useDefaultLocationsFilter) { locationQuery = locationQuery.Where(x => !(x.Name == null || x.Name.Trim() == string.Empty)); } // TODO: Remove this locationQuery = locationQuery.Where(x => x.Name == "3149-Mount Waverley" || x.Name == "3140-Lilydale"); //var locationKeys = locationQuery.Select( x => x.Id ); // // 2. Find the Group Locations that are proximate to the candidate Locations and are associated with Family Groups. // var proximateGroupLocationsBaseQuery = new GroupLocationService(context).Queryable(); // Filter for Groups that are Families. var familyGroupTypeGuid = GroupType.GROUPTYPE_FAMILY.AsGuid(); proximateGroupLocationsBaseQuery = proximateGroupLocationsBaseQuery.Where(x => x.Group.GroupType.Guid == familyGroupTypeGuid); // Filter By Location Type. if (settings.LocationTypeGuid.HasValue) { proximateGroupLocationsBaseQuery = proximateGroupLocationsBaseQuery.Where(x => x.GroupLocationTypeValue.Guid == settings.LocationTypeGuid); } // Create Queries to find Family Group Locations that are proximate to each of the candidate Locations, then return a union of the result sets. // We do this to preserve the link between the candidate Location and the Families located near that candidate Location. double proximityInMeters = 0; var locations = locationQuery.ToList(); IQueryable <PersonNearLocationResult> unionQuery = null; foreach (var l in locations) { var groupLocationPredicate = LinqPredicateBuilder.Begin <GroupLocation>(); if (l.GeoPoint != null) { var gp = l.GeoPoint; groupLocationPredicate = groupLocationPredicate.Or(gl => gl.Location.GeoPoint.Distance(gp) <= proximityInMeters); } if (l.GeoFence != null) { var gf = l.GeoFence; groupLocationPredicate = groupLocationPredicate.Or(gl => gl.Location.GeoPoint != null && gl.Location.GeoPoint.Intersects(gf) || gl.Location.GeoPoint.Distance(gf) <= proximityInMeters); groupLocationPredicate = groupLocationPredicate.Or(gl => gl.Location.GeoFence != null && gl.Location.GeoFence.Intersects(gf) || gl.Location.GeoFence.Distance(gf) <= proximityInMeters); } var proximateGroupLocationsQuery = proximateGroupLocationsBaseQuery.Where(groupLocationPredicate); // Return all of the People in the Groups identified in the Group Locations, and the set of candidate Locations their Family Group is associated with. var groupMembersOfProximateLocations = new GroupMemberService(context).Queryable() .Where(gm => proximateGroupLocationsQuery.Select(gl => gl.GroupId).Contains(gm.GroupId)); // // ** This Query produces the correct results. // string locationName = l.ToString(); var personLocationsQuery = new PersonService(context).Queryable() .Where(p => groupMembersOfProximateLocations.Select(gm => gm.PersonId).Contains(p.Id)) .Select(x => new PersonNearLocationResult { Person = x, LocationName = locationName }); //var result5 = personLocationsQuery.ToList(); if (unionQuery == null) { unionQuery = personLocationsQuery; } else { unionQuery = unionQuery.Union(personLocationsQuery); } } //var finalQuery = unionQuery.Select(pnl => unionQuery.Where(uq => uq.Person.Id == pnl.Person.Id).Select(p => p.LocationName)); //var resultUnion = unionQuery.ToList(); var finalQuery = new PersonService(context).Queryable().Select(p => unionQuery.Where(uq => uq.Person.Id == p.Id).Select(x => x.LocationName)); //var result6 = finalQuery.Where( x => x.Any() ).ToList(); // Define the Select Expression containing the field output. var selectExpression = SelectExpressionExtractor.Extract <Model.Person>(finalQuery, entityIdProperty, "p"); return(selectExpression); }