/// <summary> /// Determines whether [is view in filter] [the specified data view id]. /// </summary> /// <param name="dataViewId">The data view id.</param> /// <param name="filter">The filter.</param> /// <returns> /// <c>true</c> if [is view in filter] [the specified data view id]; otherwise, <c>false</c>. /// </returns> private bool IsViewInFilter(int dataViewId, Rock.Model.DataViewFilter filter) { if (filter.EntityTypeId.HasValue) { var entityType = EntityTypeCache.Get(filter.EntityTypeId.Value); var component = Rock.Reporting.DataFilterContainer.GetComponent(entityType.Name); if (component is OtherDataViewFilter otherDataViewFilter) { var otherDataView = otherDataViewFilter.GetSelectedDataView(filter.Selection); if (otherDataView.Id == dataViewId) { // if we discover that this DataView is also used in one of its child views, we've got infinite recursion return(true); } else { // dig down recursively thru the *other* DataView's child filters to see if any of it's child filters is using this dataview return(IsViewInFilter(dataViewId, otherDataView.DataViewFilter)); } } } foreach (var childFilter in filter.ChildFilters) { // dig down recursively thru *this* DataView's child filters if (IsViewInFilter(dataViewId, childFilter)) { return(true); } } return(false); }
/// <summary> /// Reset all of the identifiers on a DataViewFilter that uniquely identify it in the permanent store. /// </summary> /// <param name="filter">The data view filter.</param> private void ResetPermanentStoreIdentifiers(DataViewFilter filter) { if (filter == null) { return; } filter.Id = 0; filter.Guid = Guid.NewGuid(); filter.ForeignId = null; filter.ForeignGuid = null; filter.ForeignKey = null; // Recursively reset any contained filters. foreach (var childFilter in filter.ChildFilters) { this.ResetPermanentStoreIdentifiers(childFilter); } }
/// <summary> /// Determines whether [is view in filter] [the specified data view id]. /// </summary> /// <param name="dataViewId">The data view id.</param> /// <param name="filter">The filter.</param> /// <returns> /// <c>true</c> if [is view in filter] [the specified data view id]; otherwise, <c>false</c>. /// </returns> private bool IsViewInFilter(int dataViewId, Rock.Model.DataViewFilter filter) { if (filter.EntityTypeId == EntityTypeCache.Read(this.GetType()).Id) { int?filterDataViewId = filter.Selection.AsIntegerOrNull(); if (filterDataViewId.HasValue) { if (filterDataViewId == dataViewId) { return(true); } } } foreach (var childFilter in filter.ChildFilters) { if (IsViewInFilter(dataViewId, childFilter)) { return(true); } } return(false); }
/// <summary> /// Determines whether [is view in filter] [the specified data view id]. /// </summary> /// <param name="dataViewId">The data view id.</param> /// <param name="filter">The filter.</param> /// <returns> /// <c>true</c> if [is view in filter] [the specified data view id]; otherwise, <c>false</c>. /// </returns> private bool IsViewInFilter(int dataViewId, Rock.Model.DataViewFilter filter) { if (filter.EntityTypeId == EntityTypeCache.Read(this.GetType()).Id) { int filterDataViewId = int.MinValue; if (int.TryParse(filter.Selection, out filterDataViewId)) { if (filterDataViewId == dataViewId) { return(true); } } } foreach (var childFilter in filter.ChildFilters) { if (IsViewInFilter(dataViewId, childFilter)) { return(true); } } return(false); }
/// <summary> /// Determines whether the specified Data View forms part of a filter. /// </summary> /// <param name="dataViewId">The unique identifier of a Data View.</param> /// <param name="filter">The filter.</param> /// <returns> /// <c>true</c> if the specified Data View forms part of the conditions for the specified filter. /// </returns> public bool IsViewInFilter(int dataViewId, DataViewFilter filter) { var dataViewFilterEntityId = new EntityTypeService(( RockContext )this.Context).Get(typeof(OtherDataViewFilter), false, null).Id; return(IsViewInFilter(dataViewId, filter, dataViewFilterEntityId)); }
/// <summary> /// Gets the expression. /// </summary> /// <param name="serviceInstance">The service instance.</param> /// <param name="paramExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <returns></returns> /// <exception cref="Rock.Reporting.RockReportingException"> /// Unable to determine Assembly for EntityTypeId { EntityTypeId } /// or /// Unable to determine DataView EntityType for { dataViewEntityTypeCache }. /// or /// Unable to determine transform expression for TransformEntityTypeId: {TransformEntityTypeId} /// </exception> public Expression GetExpression(IService serviceInstance, ParameterExpression paramExpression, DataViewFilterOverrides dataViewFilterOverrides) { var dataViewEntityTypeCache = EntityTypeCache.Get(EntityTypeId.Value); if (dataViewEntityTypeCache?.AssemblyName == null) { throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"Unable to determine DataView Assembly for EntityTypeId { EntityTypeId }"); } Type dataViewEntityTypeType = dataViewEntityTypeCache.GetEntityType(); if (dataViewEntityTypeType == null) { throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"Unable to determine DataView EntityType for { dataViewEntityTypeCache }."); } // DataViews must have a DataViewFilter (something has gone wrong it doesn't have one) // Note that DataViewFilterId might be null even though DataViewFilter is not null // This is because the DataViewFilter might be just in memory and not saved to the database (for example, a Preview or a DynamicReport) if (this.DataViewFilter == null) { throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"DataViewFilter is null for DataView { this.Name } ({this.Id})."); } bool usePersistedValues = this.PersistedScheduleIntervalMinutes.HasValue && this.PersistedLastRefreshDateTime.HasValue; if (dataViewFilterOverrides != null) { // don't use persisted values if this DataView in the list of DataViews that should not be persisted due to override usePersistedValues = usePersistedValues && !dataViewFilterOverrides.IgnoreDataViewPersistedValues.Contains(this.Id); } // If dataViewFilterOverrides is null assume true in order to preserve current functionality. RockLogger.Log.Debug(RockLogDomains.Reporting, "{methodName} dataViewFilterOverrides: {@dataViewFilterOverrides} DataviewId: {DataviewId}", nameof(GetExpression), dataViewFilterOverrides, DataViewFilter.DataViewId); if (dataViewFilterOverrides == null || dataViewFilterOverrides.ShouldUpdateStatics) { DataViewService.AddRunDataViewTransaction(Id); } // We need to call GetExpression regardless of whether or not usePresistedValues is true so the child queries get their stats updated. var filterExpression = DataViewFilter != null?DataViewFilter.GetExpression(dataViewEntityTypeType, serviceInstance, paramExpression, dataViewFilterOverrides) : null; if (usePersistedValues) { // If this is a persisted DataView, get the ids for the expression by querying DataViewPersistedValue instead of evaluating all the filters var rockContext = serviceInstance.Context as RockContext; if (rockContext == null) { rockContext = new RockContext(); } var persistedValuesQuery = rockContext.DataViewPersistedValues.Where(a => a.DataViewId == this.Id); var ids = persistedValuesQuery.Select(v => v.EntityId); MemberExpression propertyExpression = Expression.Property(paramExpression, "Id"); if (!(serviceInstance.Context is RockContext)) { // if this DataView doesn't use a RockContext get the EntityIds into memory as a List<int> then back into IQueryable<int> so that we aren't use multiple dbContexts ids = ids.ToList().AsQueryable(); } var idsExpression = Expression.Constant(ids.AsQueryable(), typeof(IQueryable <int>)); Expression expression = Expression.Call(typeof(Queryable), "Contains", new Type[] { typeof(int) }, idsExpression, propertyExpression); return(expression); } else { if (dataViewEntityTypeCache.Id == EntityTypeCache.Get(typeof(Rock.Model.Person)).Id) { var qry = new PersonService(( RockContext )serviceInstance.Context).Queryable(this.IncludeDeceased); Expression extractedFilterExpression = FilterExpressionExtractor.Extract <Rock.Model.Person>(qry, paramExpression, "p"); if (filterExpression == null) { filterExpression = extractedFilterExpression; } else { filterExpression = Expression.AndAlso(filterExpression, extractedFilterExpression); } } if (this.TransformEntityTypeId.HasValue) { Expression transformedExpression = GetTransformExpression(this.TransformEntityTypeId.Value, serviceInstance, paramExpression, filterExpression); if (transformedExpression == null) { // if TransformEntityTypeId is defined, but we got null back, we'll get unexpected results, so throw an exception throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"Unable to determine transform expression for TransformEntityTypeId: {TransformEntityTypeId}"); } return(transformedExpression); } return(filterExpression); } }
/// <summary> /// Gets the expression. /// </summary> /// <param name="serviceInstance">The service instance.</param> /// <param name="paramExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public Expression GetExpression(IService serviceInstance, ParameterExpression paramExpression, DataViewFilterOverrides dataViewFilterOverrides, out List <string> errorMessages) { errorMessages = new List <string>(); var cachedEntityType = EntityTypeCache.Get(EntityTypeId.Value); if (cachedEntityType?.AssemblyName == null) { return(null); } Type filteredEntityType = cachedEntityType.GetEntityType(); if (filteredEntityType == null) { return(null); } bool usePersistedValues = this.PersistedScheduleIntervalMinutes.HasValue && this.PersistedLastRefreshDateTime.HasValue; if (dataViewFilterOverrides != null) { // don't use persisted values if this dataview is in the list of dataviews that should not be persisted due to override usePersistedValues = usePersistedValues && !dataViewFilterOverrides.IgnoreDataViewPersistedValues.Contains(this.Id); } DataViewService.AddRunDataViewTransaction(Id); if (usePersistedValues) { // If this is a persisted dataview, get the ids for the expression by querying DataViewPersistedValue instead of evaluating all the filters var rockContext = serviceInstance.Context as RockContext; if (rockContext == null) { rockContext = new RockContext(); } var persistedValuesQuery = rockContext.DataViewPersistedValues.Where(a => a.DataViewId == this.Id); var ids = persistedValuesQuery.Select(v => v.EntityId); MemberExpression propertyExpression = Expression.Property(paramExpression, "Id"); if (!(serviceInstance.Context is RockContext)) { // if this DataView doesn't use a RockContext get the EntityIds into memory as as a List<int> then back into IQueryable<int> so that we aren't use multiple dbContexts ids = ids.ToList().AsQueryable(); } var idsExpression = Expression.Constant(ids.AsQueryable(), typeof(IQueryable <int>)); Expression expression = Expression.Call(typeof(Queryable), "Contains", new Type[] { typeof(int) }, idsExpression, propertyExpression); return(expression); } else { Expression filterExpression = DataViewFilter != null?DataViewFilter.GetExpression(filteredEntityType, serviceInstance, paramExpression, dataViewFilterOverrides, errorMessages) : null; if (cachedEntityType.Id == EntityTypeCache.Get(typeof(Rock.Model.Person)).Id) { var qry = new PersonService(( RockContext )serviceInstance.Context).Queryable(this.IncludeDeceased); Expression extractedFilterExpression = FilterExpressionExtractor.Extract <Rock.Model.Person>(qry, paramExpression, "p"); if (filterExpression == null) { filterExpression = extractedFilterExpression; } else { filterExpression = Expression.AndAlso(filterExpression, extractedFilterExpression); } } Expression transformedExpression = GetTransformExpression(serviceInstance, paramExpression, filterExpression, errorMessages); if (transformedExpression != null) { return(transformedExpression); } return(filterExpression); } }
/// <summary> /// Gets the expression. /// </summary> /// <param name="serviceInstance">The service instance.</param> /// <param name="paramExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public Expression GetExpression(IService serviceInstance, ParameterExpression paramExpression, DataViewFilterOverrides dataViewFilterOverrides, out List <string> errorMessages) { errorMessages = new List <string>(); var cachedEntityType = EntityTypeCache.Get(EntityTypeId.Value); if (cachedEntityType != null && cachedEntityType.AssemblyName != null) { Type filteredEntityType = cachedEntityType.GetEntityType(); if (filteredEntityType != null) { bool usePersistedValues = this.PersistedScheduleIntervalMinutes.HasValue && this.PersistedLastRefreshDateTime.HasValue; if (dataViewFilterOverrides != null) { usePersistedValues = usePersistedValues && !dataViewFilterOverrides.IgnoreDataViewPersistedValues.Contains(this.Id); } // don't use persisted values if there are dataViewFilterOverrides if (usePersistedValues && dataViewFilterOverrides?.Any() == true) { usePersistedValues = false; } if (usePersistedValues) { // If this is a persisted dataview, get the ids for the expression by querying DataViewPersistedValue instead of evaluating all the filters var rockContext = serviceInstance.Context as RockContext; if (rockContext == null) { rockContext = new RockContext(); } var persistedValuesQuery = rockContext.DataViewPersistedValues.Where(a => a.DataViewId == this.Id); var ids = persistedValuesQuery.Select(v => v.EntityId); MemberExpression propertyExpression = Expression.Property(paramExpression, "Id"); if (!(serviceInstance.Context is RockContext)) { // if this DataView doesn't use a RockContext get the EntityIds into memory as as a List<int> then back into IQueryable<int> so that we aren't use multiple dbContexts ids = ids.ToList().AsQueryable(); } var idsExpression = Expression.Constant(ids.AsQueryable(), typeof(IQueryable <int>)); Expression expression = Expression.Call(typeof(Queryable), "Contains", new Type[] { typeof(int) }, idsExpression, propertyExpression); return(expression); } else { Expression filterExpression = DataViewFilter != null?DataViewFilter.GetExpression(filteredEntityType, serviceInstance, paramExpression, dataViewFilterOverrides, errorMessages) : null; Expression transformedExpression = GetTransformExpression(serviceInstance, paramExpression, filterExpression, errorMessages); if (transformedExpression != null) { return(transformedExpression); } return(filterExpression); } } } return(null); }
/// <summary> /// Determines whether the specified Data View forms part of a filter. /// </summary> /// <param name="dataViewId">The unique identifier of a Data View.</param> /// <param name="filter">The filter.</param> /// <returns> /// <c>true</c> if the specified Data View forms part of the conditions for the specified filter. /// </returns> public bool IsViewInFilter(int dataViewId, DataViewFilter filter) { var dataView = Get(dataViewId); return(IsViewInFilter(dataView, filter)); }