/// <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<Rock.Model.Group>( resultQuery, entityIdProperty, "p" );
return selectExpression;
}