/// <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);
        }
Exemple #2
0
        /// <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);
        }
Exemple #3
0
        /// <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));
        }
Exemple #4
0
        /// <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);
        }
Exemple #5
0
        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);
        }