コード例 #1
0
        public override bool Execute(RockContext rockContext, WorkflowAction action, object entity, out List <string> errorMessages)
        {
            errorMessages = new List <string>();

            EntityTypeCache cachedEntityType = EntityTypeCache.Read(GetAttributeValue(action, "EntityType").AsGuid());

            if (cachedEntityType != null)
            {
                Type entityType = cachedEntityType.GetEntityType();
                var  newEntity  = (IEntity)Activator.CreateInstance(entityType);

                var propertyValues = GetAttributeValue(action, "EntityProperties").Replace(" ! ", " | ").ResolveMergeFields(GetMergeFields(action)).TrimEnd('|').Split('|').Select(p => p.Split('^')).Select(p => new { Name = p[0], Value = p[1] });
                foreach (var prop in propertyValues)
                {
                    PropertyInfo propInf = entityType.GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
                    if (null != propInf && propInf.CanWrite)
                    {
                        if (!(GetAttributeValue(action, "EmptyValueHandling") == "IGNORE" && string.IsNullOrWhiteSpace(prop.Value)))
                        {
                            try
                            {
                                propInf.SetValue(newEntity, ObjectConverter.ConvertObject(prop.Value, propInf.PropertyType, GetAttributeValue(action, "EmptyValueHandling") == "NULL"), null);
                            }
                            catch (Exception ex) when(ex is InvalidCastException || ex is FormatException || ex is OverflowException)
                            {
                                errorMessages.Add("Invalid Property Value: " + prop.Name + ": " + ex.Message);
                            }
                        }
                    }
                    else
                    {
                        errorMessages.Add("Invalid Property: " + prop.Name);
                    }
                }

                rockContext.Set(entityType).Add(newEntity);
                rockContext.SaveChanges();

                // If request attribute was specified, requery the request and set the attribute's value
                Guid?entityAttributeGuid = GetAttributeValue(action, "EntityAttribute").AsGuidOrNull();
                if (entityAttributeGuid.HasValue)
                {
                    newEntity = (IEntity)rockContext.Set(entityType).Find(new[] { newEntity.Id });
                    if (newEntity != null)
                    {
                        SetWorkflowAttributeValue(action, entityAttributeGuid.Value, newEntity.Guid.ToString());
                    }
                }


                return(true);
            }

            errorMessages.Add("Invalid Entity Attribute");
            return(false);
        }
コード例 #2
0
ファイル: FamilyNameSelect.cs プロジェクト: MrUpsideDown/Rock
        /// <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>
        public override Expression GetExpression(RockContext context, MemberExpression entityIdProperty, string selection)
        {
            // groupmembers
            var groupMembers = context.Set <Rock.Model.GroupMember>();

            // m
            ParameterExpression groupMemberParameter = Expression.Parameter(typeof(Rock.Model.GroupMember), "m");

            // m.PersonId
            MemberExpression memberPersonIdProperty = Expression.Property(groupMemberParameter, "PersonId");

            // m.Group
            MemberExpression groupProperty = Expression.Property(groupMemberParameter, "Group");

            // m.Group.GroupType
            MemberExpression groupTypeProperty = Expression.Property(groupProperty, "GroupType");

            // m.Group.GroupType.Guid
            MemberExpression groupTypeGuidProperty = Expression.Property(groupTypeProperty, "Guid");

            // family group type guid
            Expression groupTypeConstant = Expression.Constant(Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY.AsGuid());

            // m.PersonId == p.Id
            Expression personCompare = Expression.Equal(memberPersonIdProperty, entityIdProperty);

            // m.Group.GroupType.Guid == GROUPTYPE_FAMILY guid
            Expression groupTypeCompare = Expression.Equal(groupTypeGuidProperty, groupTypeConstant);

            // m.PersonID == p.Id && m.Group.GroupType.Guid == GROUPTYPE_FAMILY guid
            Expression andExpression = Expression.And(personCompare, groupTypeCompare);


            // m => m.PersonID == p.Id && m.Group.GroupType.Guid == GROUPTYPE_FAMILY guid
            var compare = new Expression[] {
                Expression.Constant(groupMembers),
                Expression.Lambda <Func <Rock.Model.GroupMember, bool> >(andExpression, new ParameterExpression[] { groupMemberParameter })
            };

            // groupmembers.Where(m => m.PersonID == p.Id && m.Group.GroupType.Guid == GROUPTYPE_FAMILY guid)
            Expression whereExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(Rock.Model.GroupMember) }, compare);

            // m.Group.Name
            MemberExpression groupName = Expression.Property(groupProperty, "Name");

            // m => m.Group.Name
            Expression groupNameLambda = Expression.Lambda(groupName, new ParameterExpression[] { groupMemberParameter });

            // groupmembers.Where(m => m.PersonID == p.Id && m.Group.GroupType.Guid == GROUPTYPE_FAMILY guid).Select( m => m.Group.Name);
            Expression selectName = Expression.Call(typeof(Queryable), "Select", new Type[] { typeof(Rock.Model.GroupMember), typeof(string) }, whereExpression, groupNameLambda);

            // groupmembers.Where(m => m.PersonID == p.Id && m.Group.GroupType.Guid == GROUPTYPE_FAMILY guid).Select( m => m.Group.Name).FirstOrDefault();
            Expression firstOrDefault = Expression.Call(typeof(Queryable), "FirstOrDefault", new Type[] { typeof(string) }, selectName);

            return(firstOrDefault);
        }
コード例 #3
0
        /// <summary>
        /// Gets the expression.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="entityIdProperty">The entity identifier property.</param>
        /// <param name="selection"></param>
        /// <returns></returns>
        public override Expression GetExpression(RockContext context, Expression entityIdProperty, string selection)
        {
            // transactions
            var transactionDetails = context.Set <FinancialTransactionDetail>();

            // t
            ParameterExpression transactionDetailParameter = Expression.Parameter(typeof(FinancialTransactionDetail), "t");

            // t.Transaction
            MemberExpression transactionProperty = Expression.Property(transactionDetailParameter, "Transaction");

            // t.Transaction.AuthorizedPersonId
            MemberExpression authorizedPersonIdProperty = Expression.Property(transactionProperty, "AuthorizedPersonId");

            // t.Transaction.AuthorizedPersonId == Convert(p.Id)
            Expression whereClause = Expression.Equal(authorizedPersonIdProperty, Expression.Convert(entityIdProperty, typeof(int?)));

            // get the selected AccountId(s).  If there are any, limit to transactions that for that Account
            if (!string.IsNullOrWhiteSpace(selection))
            {
                // accountIds
                var selectedAccountIdList = selection.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(a => a.AsInteger() ?? 0).ToList();
                if (selectedAccountIdList.Count() > 0)
                {
                    // t.AccountId
                    MemberExpression accountIdProperty = Expression.Property(transactionDetailParameter, "AccountId");

                    // accountIds.Contains(t.AccountId)
                    Expression selectedAccountIds = Expression.Constant(selectedAccountIdList);
                    Expression containsExpression = Expression.Call(selectedAccountIds, "Contains", new Type[] {}, accountIdProperty);

                    // t.authorizedPersonId == Convert(p.Id) && accountIds.Contains(t.AccountId)
                    whereClause = Expression.And(whereClause, containsExpression);
                }
            }

            // t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            var compare = new Expression[] {
                Expression.Constant(transactionDetails),
                Expression.Lambda <Func <FinancialTransactionDetail, bool> >(whereClause, new ParameterExpression[] { transactionDetailParameter })
            };

            // transactions.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            Expression whereExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(FinancialTransactionDetail) }, compare);

            // t.Transaction.TransactionDateTime
            MemberExpression transactionDateTime = Expression.Property(transactionProperty, "TransactionDateTime");

            // t => t.Transaction.transactionDateTime
            var transactionDate = Expression.Lambda <Func <FinancialTransactionDetail, DateTime?> >(transactionDateTime, new ParameterExpression[] { transactionDetailParameter });

            // transaction.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id).Max( t => t.Transaction.transactionDateTime)
            Expression maxExpression = Expression.Call(typeof(Queryable), "Max", new Type[] { typeof(FinancialTransactionDetail), typeof(DateTime? ) }, whereExpression, transactionDate);

            return(maxExpression);
        }
コード例 #4
0
        /// <summary>
        /// Gets the expression.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="entityIdProperty">The entity identifier property.</param>
        /// <param name="selection"></param>
        /// <returns></returns>
        public override Expression GetExpression(RockContext context, MemberExpression entityIdProperty, string selection)
        {
            // transactions
            var transactionDetails = context.Set <FinancialTransactionDetail>();

            // t
            ParameterExpression transactionDetailParameter = Expression.Parameter(typeof(FinancialTransactionDetail), "t");

            // t.Transaction
            MemberExpression transactionProperty = Expression.Property(transactionDetailParameter, "Transaction");

            // t.Transaction.AuthorizedPersonAlias
            MemberExpression authorizedPersonAliasProperty = Expression.Property(transactionProperty, "AuthorizedPersonAlias");

            // t.Transaction.AuthorizedPersonAlias.PersonId
            MemberExpression authorizedPersonIdProperty = Expression.Property(authorizedPersonAliasProperty, "PersonId");

            // t.Transaction.AuthorizedPersonAlias.PersonId == Convert(p.Id)
            Expression whereClause = Expression.Equal(authorizedPersonIdProperty, Expression.Convert(entityIdProperty, typeof(int)));

            // t.Transaction.TransactionTypeValueId
            MemberExpression transactionTypeValueIdProperty = Expression.Property(transactionProperty, "TransactionTypeValueId");

            int transactionTypeContributionId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid()).Id;

            // t.Transaction.TransactionTypeValueId == transactionTypeContributionId
            whereClause = Expression.And(whereClause, Expression.Equal(transactionTypeValueIdProperty, Expression.Constant(transactionTypeContributionId)));

            // get the selected AccountId(s).  If there are any, limit to transactions that for that Account
            if (!string.IsNullOrWhiteSpace(selection))
            {
                // accountIds
                var selectedAccountGuidList = selection.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).AsGuidList();
                var selectedAccountIdList   = new FinancialAccountService(context).GetByGuids(selectedAccountGuidList).Select(a => a.Id).ToList();

                if (selectedAccountIdList.Count() > 0)
                {
                    // t.AccountId
                    MemberExpression accountIdProperty = Expression.Property(transactionDetailParameter, "AccountId");

                    // accountIds.Contains(t.AccountId)
                    Expression selectedAccountIds = Expression.Constant(selectedAccountIdList);
                    Expression containsExpression = Expression.Call(selectedAccountIds, "Contains", new Type[] { }, accountIdProperty);

                    // t.authorizedPersonId == Convert(p.Id) && accountIds.Contains(t.AccountId)
                    whereClause = Expression.And(whereClause, containsExpression);
                }
            }

            // t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            var compare = new Expression[] {
                Expression.Constant(transactionDetails),
                Expression.Lambda <Func <FinancialTransactionDetail, bool> >(whereClause, new ParameterExpression[] { transactionDetailParameter })
            };

            // transactions.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            Expression whereExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(FinancialTransactionDetail) }, compare);

            // t.Transaction.TransactionDateTime
            MemberExpression transactionDateTime = Expression.Property(transactionProperty, "SundayDate");

            // t => t.Transaction.transactionDateTime
            var transactionDate = Expression.Lambda <Func <FinancialTransactionDetail, DateTime?> >(transactionDateTime, new ParameterExpression[] { transactionDetailParameter });

            // transaction.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id).Max( t => t.Transaction.transactionDateTime)
            string     methodName       = FirstOrLast == FirstLast.Last ? "Max" : "Min";
            Expression maxMinExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { typeof(FinancialTransactionDetail), typeof(DateTime? ) }, whereExpression, transactionDate);

            return(maxMinExpression);
        }
コード例 #5
0
ファイル: RockEntity.cs プロジェクト: ewin66/rockrms
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        /// <exception cref="System.Exception">Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.</exception>
        public override void Render(Context context, TextWriter result)
        {
            // first ensure that entity commands are allowed in the context
            if (!this.IsAuthorized(context))
            {
                result.Write(string.Format(RockLavaBlockBase.NotAuthorizedMessage, this.Name));
                base.Render(context, result);
                return;
            }

            bool hasFilter = false;

            // get a service for the entity based off it's friendly name
            var entityTypes = EntityTypeCache.All();

            var model = string.Empty;

            if (_entityName == "business")
            {
                model = "Rock.Model.Person";
            }
            else
            {
                model = "Rock.Model." + _entityName;
            }

            // Check first to see if this is a core model
            var entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, model, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

            // If not, look for first plugin model that has same friendly name
            if (entityTypeCache == null)
            {
                entityTypeCache = entityTypes
                                  .Where(e =>
                                         e.IsEntity &&
                                         !e.Name.StartsWith("Rock.Model") &&
                                         e.FriendlyName != null &&
                                         e.FriendlyName.RemoveSpaces().ToLower() == _entityName)
                                  .OrderBy(e => e.Id)
                                  .FirstOrDefault();
            }

            // If still null check to see if this was a duplicate class and full class name was used as entity name
            if (entityTypeCache == null)
            {
                model           = _entityName.Replace('_', '.');
                entityTypeCache = entityTypes.Where(e => String.Equals(e.Name, model, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
            }

            if (entityTypeCache != null)
            {
                Type entityType = entityTypeCache.GetEntityType();
                if (entityType != null)
                {
                    // Get the database context
                    Type contextType = null;
                    Rock.Data.DbContext dbContext = null;
                    var contexts = Rock.Reflection.SearchAssembly(entityType.Assembly, typeof(Rock.Data.DbContext));
                    if (contexts.Any())
                    {
                        contextType = contexts.First().Value;
                        dbContext   = Activator.CreateInstance(contextType) as Rock.Data.DbContext;
                    }
                    if (dbContext == null)
                    {
                        dbContext = _rockContext;
                    }

                    // create an instance of the entity's service
                    Type[]             modelType          = { entityType };
                    Type               genericServiceType = typeof(Rock.Data.Service <>);
                    Type               modelServiceType   = genericServiceType.MakeGenericType(modelType);
                    Rock.Data.IService serviceInstance    = Activator.CreateInstance(modelServiceType, new object[] { dbContext }) as IService;

                    ParameterExpression paramExpression = Expression.Parameter(entityType, "x");
                    Expression          queryExpression = null; // the base expression we'll use to build our query from

                    // parse markup
                    var parms = ParseMarkup(_markup, context);

                    if (parms.Any(p => p.Key == "id"))
                    {
                        string propertyName = "Id";

                        List <string> selectionParms = new List <string>();
                        selectionParms.Add(PropertyComparisonConverstion("==").ToString());
                        selectionParms.Add(parms["id"].ToString());
                        selectionParms.Add(propertyName);

                        var entityProperty = entityType.GetProperty(propertyName);
                        queryExpression = ExpressionHelper.PropertyFilterExpression(selectionParms, paramExpression, propertyName, entityProperty.PropertyType);

                        hasFilter = true;
                    }
                    else
                    {
                        // where clause expression
                        if (parms.Any(p => p.Key == "where"))
                        {
                            queryExpression = ParseWhere(parms["where"], entityType, serviceInstance, paramExpression, entityType, entityTypeCache);

                            if (queryExpression != null)
                            {
                                hasFilter = true;
                            }
                        }

                        // dataview expression
                        if (parms.Any(p => p.Key == "dataview"))
                        {
                            var dataViewId = parms["dataview"].AsIntegerOrNull();

                            if (dataViewId.HasValue)
                            {
                                var dataViewExpression = GetDataViewExpression(dataViewId.Value, serviceInstance, paramExpression, entityTypeCache);

                                if (queryExpression == null)
                                {
                                    queryExpression = dataViewExpression;
                                    hasFilter       = true;
                                }
                                else
                                {
                                    queryExpression = Expression.AndAlso(queryExpression, dataViewExpression);
                                }
                            }
                        }

                        // process dynamic filter expressions (from the query string)
                        if (parms.Any(p => p.Key == "dynamicparameters"))
                        {
                            var dynamicFilters = parms["dynamicparameters"].Split(',')
                                                 .Select(x => x.Trim())
                                                 .Where(x => !string.IsNullOrWhiteSpace(x))
                                                 .ToList();

                            foreach (var dynamicFilter in dynamicFilters)
                            {
                                var dynamicFilterValue      = HttpContext.Current.Request[dynamicFilter];
                                var dynamicFilterExpression = GetDynamicFilterExpression(dynamicFilter, dynamicFilterValue, entityType, serviceInstance, paramExpression);
                                if (dynamicFilterExpression != null)
                                {
                                    if (queryExpression == null)
                                    {
                                        queryExpression = dynamicFilterExpression;
                                        hasFilter       = true;
                                    }
                                    else
                                    {
                                        queryExpression = Expression.AndAlso(queryExpression, dynamicFilterExpression);
                                    }
                                }
                            }
                        }
                    }

                    // make the query from the expression
                    MethodInfo getMethod = serviceInstance.GetType().GetMethod("Get", new Type[] { typeof(ParameterExpression), typeof(Expression), typeof(Rock.Web.UI.Controls.SortProperty), typeof(int?) });
                    if (getMethod != null)
                    {
                        var queryResult = getMethod.Invoke(serviceInstance, new object[] { paramExpression, queryExpression, null, null }) as IQueryable <IEntity>;

                        // process entity specific filters
                        switch (_entityName)
                        {
                        case "person":
                        {
                            queryResult = PersonFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }

                        case "business":
                        {
                            queryResult = BusinessFilters((IQueryable <Person>)queryResult, parms);
                            break;
                        }
                        }

                        // if there was a dynamic expression add it now
                        if (parms.Any(p => p.Key == "expression"))
                        {
                            queryResult = queryResult.Where(parms["expression"]);
                            hasFilter   = true;
                        }

                        // get a listing of ids
                        if (parms.Any(p => p.Key == "ids"))
                        {
                            var value = parms["ids"].ToString().Split(',').Select(int.Parse).ToList();
                            queryResult = queryResult.Where(x => value.Contains(x.Id));
                            hasFilter   = true;
                        }

                        var queryResultExpression = queryResult.Expression;

                        // add sort expressions
                        if (parms.Any(p => p.Key == "sort"))
                        {
                            string orderByMethod = "OrderBy";


                            foreach (var column in parms["sort"].Split(',').Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList())
                            {
                                string propertyName;
                                var    direction = SortDirection.Ascending;

                                if (column.EndsWith(" desc", StringComparison.OrdinalIgnoreCase))
                                {
                                    direction    = SortDirection.Descending;
                                    propertyName = column.Left(column.Length - 5);
                                }
                                else
                                {
                                    propertyName = column;
                                }

                                string methodName = direction == SortDirection.Descending ? orderByMethod + "Descending" : orderByMethod;

                                if (entityType.GetProperty(propertyName) != null)
                                {
                                    // sorting a entity property
                                    var memberExpression          = Expression.Property(paramExpression, propertyName);
                                    LambdaExpression sortSelector = Expression.Lambda(memberExpression, paramExpression);
                                    queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                }
                                else
                                {
                                    // sorting on an attribute

                                    // get attribute id
                                    int?attributeId = null;
                                    foreach (var id in AttributeCache.GetByEntity(entityTypeCache.Id).SelectMany(a => a.AttributeIds))
                                    {
                                        var attribute = AttributeCache.Get(id);
                                        if (attribute.Key == propertyName)
                                        {
                                            attributeId = id;
                                        }
                                    }

                                    if (attributeId.HasValue)
                                    {
                                        // get AttributeValue queryable and parameter
                                        var attributeValues = _rockContext.Set <AttributeValue>();
                                        ParameterExpression attributeValueParameter = Expression.Parameter(typeof(AttributeValue), "v");
                                        MemberExpression    idExpression            = Expression.Property(paramExpression, "Id");
                                        var attributeExpression = Attribute.Helper.GetAttributeValueExpression(attributeValues, attributeValueParameter, idExpression, attributeId.Value);

                                        LambdaExpression sortSelector = Expression.Lambda(attributeExpression, paramExpression);
                                        queryResultExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { queryResult.ElementType, sortSelector.ReturnType }, queryResultExpression, sortSelector);
                                    }
                                }

                                orderByMethod = "ThenBy";
                            }
                        }

                        // reassemble the queryable with the sort expressions
                        queryResult = queryResult.Provider.CreateQuery(queryResultExpression) as IQueryable <IEntity>;

                        if (parms.GetValueOrNull("count").AsBoolean())
                        {
                            int countResult = queryResult.Count();
                            context.Scopes.Last()["count"] = countResult;
                        }
                        else
                        {
                            // run security check on each result
                            var items        = queryResult.ToList();
                            var itemsSecured = new List <IEntity>();

                            Person person = GetCurrentPerson(context);

                            foreach (IEntity item in items)
                            {
                                ISecured itemSecured = item as ISecured;
                                if (itemSecured == null || itemSecured.IsAuthorized(Authorization.VIEW, person))
                                {
                                    itemsSecured.Add(item);
                                }
                            }

                            queryResult = itemsSecured.AsQueryable();

                            // offset
                            if (parms.Any(p => p.Key == "offset"))
                            {
                                queryResult = queryResult.Skip(parms["offset"].AsInteger());
                            }

                            // limit, default to 1000
                            if (parms.Any(p => p.Key == "limit"))
                            {
                                queryResult = queryResult.Take(parms["limit"].AsInteger());
                            }
                            else
                            {
                                queryResult = queryResult.Take(1000);
                            }

                            // check to ensure we had some form of filter (otherwise we'll return all results in the table)
                            if (!hasFilter)
                            {
                                throw new Exception("Your Lava command must contain at least one valid filter. If you configured a filter it's possible that the property or attribute you provided does not exist.");
                            }

                            var resultList = queryResult.ToList();

                            // if there is only one item to return set an alternative non-array based variable
                            if (resultList.Count == 1)
                            {
                                context.Scopes.Last()[_entityName] = resultList.FirstOrDefault();
                            }

                            context.Scopes.Last()[parms["iterator"]] = resultList;
                        }
                    }
                }
            }
            else
            {
                result.Write(string.Format("Could not find a model for {0}.", _entityName));
                base.Render(context, result);
            }

            base.Render(context, result);
        }
コード例 #6
0
        /// <summary>
        /// Gets the data source.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="entityFields">The entity fields.</param>
        /// <param name="attributes">The attributes.</param>
        /// <param name="selectComponents">The select components.</param>
        /// <param name="sortProperty">The sort property.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public List <object> GetDataSource(RockContext context, Type entityType, Dictionary <int, EntityField> entityFields, Dictionary <int, AttributeCache> attributes, Dictionary <int, ReportField> selectComponents, Rock.Web.UI.Controls.SortProperty sortProperty, out List <string> errorMessages)
        {
            errorMessages = new List <string>();

            if (entityType != null)
            {
                Type[] modelType          = { entityType };
                Type   genericServiceType = typeof(Rock.Data.Service <>);
                Type   modelServiceType   = genericServiceType.MakeGenericType(modelType);

                object serviceInstance = Activator.CreateInstance(modelServiceType, new object[] { context });

                if (serviceInstance != null)
                {
                    ParameterExpression paramExpression = serviceInstance.GetType().GetProperty("ParameterExpression").GetValue(serviceInstance) as ParameterExpression;
                    MemberExpression    idExpression    = Expression.Property(paramExpression, "Id");

                    // Get AttributeValue queryable and parameter
                    var attributeValues = context.Set <AttributeValue>();
                    ParameterExpression attributeValueParameter = Expression.Parameter(typeof(AttributeValue), "v");

                    // Create the dynamic type
                    var dynamicFields = new Dictionary <string, Type>();
                    foreach (var f in entityFields)
                    {
                        dynamicFields.Add(string.Format("Entity_{0}_{1}", f.Value.Name, f.Key), f.Value.PropertyType);
                    }

                    foreach (var a in attributes)
                    {
                        dynamicFields.Add(string.Format("Attribute_{0}_{1}", a.Value.Id, a.Key), typeof(string));
                    }

                    foreach (var reportField in selectComponents)
                    {
                        DataSelectComponent selectComponent = DataSelectContainer.GetComponent(reportField.Value.DataSelectComponentEntityType.Name);
                        if (selectComponent != null)
                        {
                            dynamicFields.Add(string.Format("Data_{0}_{1}", selectComponent.ColumnPropertyName, reportField.Key), selectComponent.ColumnFieldType);
                        }
                    }

                    if (dynamicFields.Count == 0)
                    {
                        errorMessages.Add("At least one field must be defined");
                        return(null);
                    }

                    Type            dynamicType      = LinqRuntimeTypeBuilder.GetDynamicType(dynamicFields);
                    ConstructorInfo methodFromHandle = dynamicType.GetConstructor(Type.EmptyTypes);

                    // Bind the dynamic fields to their expressions
                    var bindings = new List <MemberBinding>();
                    foreach (var f in entityFields)
                    {
                        bindings.Add(Expression.Bind(dynamicType.GetField(string.Format("entity_{0}_{1}", f.Value.Name, f.Key)), Expression.Property(paramExpression, f.Value.Name)));
                    }

                    foreach (var a in attributes)
                    {
                        bindings.Add(Expression.Bind(dynamicType.GetField(string.Format("attribute_{0}_{1}", a.Value.Id, a.Key)), GetAttributeValueExpression(attributeValues, attributeValueParameter, idExpression, a.Value.Id)));
                    }
                    foreach (var reportField in selectComponents)
                    {
                        DataSelectComponent selectComponent = DataSelectContainer.GetComponent(reportField.Value.DataSelectComponentEntityType.Name);
                        if (selectComponent != null)
                        {
                            bindings.Add(Expression.Bind(dynamicType.GetField(string.Format("data_{0}_{1}", selectComponent.ColumnPropertyName, reportField.Key)), selectComponent.GetExpression(context, idExpression, reportField.Value.Selection)));
                        }
                    }

                    ConstructorInfo      constructorInfo      = dynamicType.GetConstructor(Type.EmptyTypes);
                    NewExpression        newExpression        = Expression.New(constructorInfo);
                    MemberInitExpression memberInitExpression = Expression.MemberInit(newExpression, bindings);
                    Expression           selector             = Expression.Lambda(memberInitExpression, paramExpression);
                    Expression           whereExpression      = this.DataView.GetExpression(serviceInstance, paramExpression, out errorMessages);

                    MethodInfo getMethod = serviceInstance.GetType().GetMethod("Get", new Type[] { typeof(ParameterExpression), typeof(Expression), typeof(Rock.Web.UI.Controls.SortProperty) });
                    if (getMethod != null)
                    {
                        var getResult = getMethod.Invoke(serviceInstance, new object[] { paramExpression, whereExpression, sortProperty });
                        var qry       = getResult as IQueryable <IEntity>;

                        var selectExpression = Expression.Call(typeof(Queryable), "Select", new Type[] { qry.ElementType, dynamicType }, Expression.Constant(qry), selector);
                        var query            = qry.Provider.CreateQuery(selectExpression).AsNoTracking();

                        // enumerate thru the query results and put into a list
                        var reportResult = new List <object>();
                        var enumerator   = query.GetEnumerator();
                        while (enumerator.MoveNext())
                        {
                            reportResult.Add(enumerator.Current);
                        }

                        return(reportResult);
                    }
                }
            }

            return(null);
        }