static int?DetermineMinMaxValue(IEnumerable <QueryComposerTermDTO> terms)
        {
            int?value = null;

            foreach (var term in terms)
            {
                AgeRangeValues v = AdapterHelpers.ParseAgeRangeValues(term);
                if (v.MaxAge.HasValue && (value == null || v.MaxAge.Value > value.Value))
                {
                    value = v.MaxAge;
                }
            }
            return(value);
        }
        public override IEnumerable <QueryComposerResponseQueryResultDTO> Execute(QueryComposerQueryDTO query, bool viewSQL)
        {
            //This is based on the xsl for QueryComposer in The ESPQueryBuilder project

            //TODO: need to see how multiple criteria are handled by the current xsl
            if (query.Where.Criteria.SelectMany(c => GetAllTermsWithinCriteria(c, ModelTermsFactory.ESPDiagnosisCodesID)).Any())
            {
                throw new NotImplementedException("The Term ESP Diagnosis Codes is currently not implemented and cannot be apart of the query.");
            }
            bool hasSQLTerm = query.Where.Criteria.SelectMany(c => GetAllTermsWithinCriteria(c, ModelTermsFactory.SqlDistributionID)).Any();

            if (hasSQLTerm)
            {
                if (query.Where.Criteria.Where(c => c.Terms.Any(d => d.Type != ModelTermsFactory.SqlDistributionID)).Any())
                {
                    throw new NotSupportedException("Another Term is Included with Sql Distribution and this is not Supported");
                }
                var    sqlCriteria = query.Where.Criteria.First().Terms.FirstOrDefault(t => t.Type == Lpp.QueryComposer.ModelTermsFactory.SqlDistributionID);
                string sql         = (sqlCriteria.GetStringValue("Sql"));

                List <DTO.QueryComposer.QueryComposerResponsePropertyDefinitionDTO> columnProperties = new List <QueryComposerResponsePropertyDefinitionDTO>();
                var results = new QueryComposerResponseQueryResultDTO {
                    ID = query.Header.ID, QueryStart = DateTimeOffset.UtcNow
                };

                List <Dictionary <string, object> > queryResults = new List <Dictionary <string, object> >();
                using (var cmd = db.Database.Connection.CreateCommand())
                {
                    cmd.CommandText = sql;
                    using (var reader = cmd.ExecuteReader(CommandBehavior.KeyInfo))
                    {
                        int       noNameIndex = 1;
                        DataTable schemaTable = reader.GetSchemaTable();
                        foreach (DataRow row in schemaTable.Rows)
                        {
                            foreach (DataColumn column in schemaTable.Columns)
                            {
                                if (column.ColumnName == "ColumnName")
                                {
                                    string columnName = row[column].ToString();
                                    if (string.IsNullOrWhiteSpace(columnName))
                                    {
                                        columnName = "NoColumnName" + noNameIndex;
                                        noNameIndex++;
                                    }
                                    columnProperties.Add(new DTO.QueryComposer.QueryComposerResponsePropertyDefinitionDTO {
                                        Name = columnName, Type = column.DataType.FullName
                                    });
                                }
                            }
                        }

                        while (reader.Read())
                        {
                            Dictionary <string, object> row = new Dictionary <string, object>();
                            //have to enumerate over the record using ordinal index since there may not be a column name in the reader
                            for (int i = 0; i < columnProperties.Count; i++)
                            {
                                row.Add(columnProperties[i].Name, reader.GetValue(i));
                            }
                            queryResults.Add(row);
                        }
                        reader.Close();
                    }
                }

                results.QueryEnd   = DateTimeOffset.UtcNow;
                results.Results    = new[] { queryResults };
                results.Properties = columnProperties;

                return(new[] { results });
            }
            else
            {
                bool hasConditionsTerm = query.Where.Criteria.SelectMany(c => GetAllTermsWithinCriteria(c, ModelTermsFactory.ConditionsID)).Any();
                bool hasICD9CodesTerm  = query.Where.Criteria.SelectMany(c => GetAllTermsWithinCriteria(c, ModelTermsFactory.ICD9DiagnosisCodes3digitID)).Any();

                var firstCriteria = query.Where.Criteria.First();
                QueryComposerTermDTO ageRangeTerm = GetAllTermsWithinCriteria(firstCriteria, ModelTermsFactory.AgeRangeID).FirstOrDefault();

                var diagnosisQuery = from d in db.Diagnosis select d;
                var diseasesQuery  = from d in db.Diseases select d;
                var encounterQuery = db.Demographics.Join(db.Encounters, o => o.PatID, i => i.PatID, (o, i) => new { o.PatID, i.EncounterID, i.AgeGroup5yr, i.AgeGroup10yr, i.A_Date, i.AgeAtEncYear });

                if (ageRangeTerm != null)
                {
                    var ageRange = AdapterHelpers.ParseAgeRangeValues(ageRangeTerm);
                    if (ageRange.MinAge.HasValue)
                    {
                        diagnosisQuery = diagnosisQuery.Where(q => q.AgeAtEncYear >= ageRange.MinAge.Value);
                        diseasesQuery  = diseasesQuery.Where(q => q.AgeAtDetectYear >= ageRange.MinAge.Value);
                        encounterQuery = encounterQuery.Where(q => q.AgeAtEncYear >= ageRange.MinAge.Value);
                    }
                    else if (ageRange.MaxAge.HasValue)
                    {
                        diagnosisQuery = diagnosisQuery.Where(q => q.AgeAtEncYear <= ageRange.MaxAge.Value);
                        diseasesQuery  = diseasesQuery.Where(q => q.AgeAtDetectYear <= ageRange.MaxAge.Value);
                        encounterQuery = encounterQuery.Where(q => q.AgeAtEncYear <= ageRange.MaxAge.Value);
                    }
                }

                //var observationPeriod = firstCriteria.Terms.FirstOrDefault(t => t.Type == ModelTermsFactory.ObservationPeriodID);
                var observationPeriod = GetAllTermsWithinCriteria(firstCriteria, ModelTermsFactory.ObservationPeriodID).FirstOrDefault();
                if (observationPeriod != null)
                {
                    var obp_range = AdapterHelpers.ParseDateRangeValues(observationPeriod);

                    if (obp_range.StartDate.HasValue)
                    {
                        int startDate = ConvertDateToNumberOfDays(obp_range.StartDate.Value);
                        diagnosisQuery = diagnosisQuery.Where(q => q.A_Date >= startDate);
                        diseasesQuery  = diseasesQuery.Where(q => q.Date >= startDate);
                        encounterQuery = encounterQuery.Where(q => q.A_Date >= startDate);
                    }
                    if (obp_range.EndDate.HasValue)
                    {
                        int endDate = ConvertDateToNumberOfDays(obp_range.EndDate.Value);
                        diagnosisQuery = diagnosisQuery.Where(q => q.A_Date <= endDate);
                        diseasesQuery  = diseasesQuery.Where(q => q.Date <= endDate);
                        encounterQuery = encounterQuery.Where(q => q.A_Date <= endDate);
                    }
                }


                //TODO: need to determine the precision of icd9 code from somewhere
                int icd9Precision = hasICD9CodesTerm ? 3 : 0;//0 == exclude, 3,4,5

                var entityQuery = from demographics in db.Demographics
                                  join race in db.UVT_Race on demographics.Race equals race.Code
                                  join sex in db.UVT_Sex on demographics.Sex equals sex.Code
                                  join ethnicity in db.UVT_Race_Ethnicity on demographics.Ethnicity equals ethnicity.Code
                                  select new ESPQueryResult
                {
                    PatientID         = demographics.PatID,
                    Patients          = null,
                    Sex               = sex.Text,
                    EthnicityCode     = demographics.Ethnicity,
                    Ethnicity         = ethnicity.Text,
                    Race              = race.Text,
                    Zip               = demographics.Zip5,
                    TobaccoUse        = demographics.Smoking,
                    Code              = null,
                    CodeDescription   = null,
                    Disease           = null,
                    ObservationPeriod = null,
                    Age_10yrGroup     = null,
                    Age_5yrGroup      = null,
                    Age_Detect        = null,
                    CenterID          = null
                };

                if (icd9Precision == 3)
                {
                    entityQuery = from o in entityQuery
                                  from diagnosis_inc in diagnosisQuery.Where(d => d.PatID == o.PatientID).DefaultIfEmpty()
                                  from dx in db.UVT_Dx3Digit.Where(x => x.Code == diagnosis_inc.DxCode3digit).DefaultIfEmpty()
                                  select new ESPQueryResult
                    {
                        PatientID     = o.PatientID,
                        Patients      = null,
                        Sex           = o.Sex,
                        EthnicityCode = o.EthnicityCode,
                        Ethnicity     = o.Ethnicity,
                        Race          = o.Race,
                        Zip           = o.Zip,
                        TobaccoUse    = o.TobaccoUse,

                        Code            = dx.Code,
                        CodeDescription = dx.Text,

                        Disease = o.Disease,
                        //NOTE: Value in db is # of days from 1960-01-01
                        ObservationPeriod = diagnosis_inc.A_Date,

                        Age_10yrGroup = diagnosis_inc.AgeGroup10yr,
                        Age_5yrGroup  = diagnosis_inc.AgeGroup5yr,
                        Age_Detect    = diagnosis_inc.AgeAtEncYear,

                        CenterID = diagnosis_inc.CenterID
                    };
                }
                else if (icd9Precision == 4)
                {
                    entityQuery = from o in entityQuery
                                  from diagnosis_inc in diagnosisQuery.Where(d => d.PatID == o.PatientID).DefaultIfEmpty()
                                  from dx in db.UVT_Dx4Digit.Where(x => x.Code == diagnosis_inc.DxCode4digitWithDec).DefaultIfEmpty()
                                  select new ESPQueryResult
                    {
                        PatientID     = o.PatientID,
                        Patients      = null,
                        Sex           = o.Sex,
                        EthnicityCode = o.EthnicityCode,
                        Ethnicity     = o.Ethnicity,
                        Race          = o.Race,
                        Zip           = o.Zip,
                        TobaccoUse    = o.TobaccoUse,

                        Code            = dx.Code,
                        CodeDescription = dx.Text,

                        Disease = o.Disease,
                        //NOTE: Value in db is # of days from 1960-01-01
                        ObservationPeriod = diagnosis_inc.A_Date,

                        Age_10yrGroup = diagnosis_inc.AgeGroup10yr,
                        Age_5yrGroup  = diagnosis_inc.AgeGroup5yr,
                        Age_Detect    = diagnosis_inc.AgeAtEncYear,

                        CenterID = diagnosis_inc.CenterID
                    };
                }
                else if (icd9Precision == 5)
                {
                    entityQuery = from o in entityQuery
                                  from diagnosis_inc in diagnosisQuery.Where(d => d.PatID == o.PatientID).DefaultIfEmpty()
                                  from dx in db.UVT_Dx5Digit.Where(x => x.Code == diagnosis_inc.DxCode5digitWithDec).DefaultIfEmpty()
                                  select new ESPQueryResult
                    {
                        PatientID     = o.PatientID,
                        Patients      = null,
                        Sex           = o.Sex,
                        EthnicityCode = o.EthnicityCode,
                        Ethnicity     = o.Ethnicity,
                        Race          = o.Race,
                        Zip           = o.Zip,
                        TobaccoUse    = o.TobaccoUse,

                        Code            = dx.Code,
                        CodeDescription = dx.Text,

                        Disease = o.Disease,
                        //NOTE: Value in db is # of days from 1960-01-01
                        ObservationPeriod = diagnosis_inc.A_Date,

                        Age_10yrGroup = diagnosis_inc.AgeGroup10yr,
                        Age_5yrGroup  = diagnosis_inc.AgeGroup5yr,
                        Age_Detect    = diagnosis_inc.AgeAtEncYear,

                        CenterID = diagnosis_inc.CenterID
                    };
                }

                if (hasConditionsTerm)
                {
                    entityQuery = from o in entityQuery
                                  from disease_inc in diseasesQuery.Where(d => d.PatID == o.PatientID).DefaultIfEmpty()
                                  select new ESPQueryResult
                    {
                        PatientID     = o.PatientID,
                        Patients      = null,
                        Sex           = o.Sex,
                        EthnicityCode = o.EthnicityCode,
                        Ethnicity     = o.Ethnicity,
                        Race          = o.Race,
                        Zip           = o.Zip,
                        TobaccoUse    = o.TobaccoUse,

                        Code            = o.Code,
                        CodeDescription = o.CodeDescription,

                        Disease = disease_inc.Condition,
                        //NOTE: Value in db is # of days from 1960-01-01
                        ObservationPeriod = disease_inc.Date,

                        Age_10yrGroup = disease_inc.AgeGroup10yr,
                        Age_5yrGroup  = disease_inc.AgeGroup5yr,
                        Age_Detect    = disease_inc.AgeAtDetectYear,

                        //center ID is not set in xsl when has visits
                        CenterID = o.CenterID
                    };
                }

                List <string> selectProperties = new List <string> {
                    "Patients"
                };                                                              //Patient aggregate is always included.

                bool primaryCriteria = true;
                foreach (var criteria in query.Where.Criteria)
                {
                    if (!primaryCriteria && criteria.Exclusion)
                    {
                        //exclusion is a not exists in the where clause
                        var subQuery = ApplyCriteria(criteria);
                        entityQuery = entityQuery.Where(q => !subQuery.Where(s => s.PatID == q.PatientID).Any());
                    }
                    else if (!primaryCriteria)
                    {
                        var subQuery = ApplyCriteria(criteria);
                        entityQuery = entityQuery.Where(q => subQuery.Where(s => s.PatID == q.PatientID).Any());
                    }
                    else
                    {
                        primaryCriteria = false;
                        //process the first criteria as the primary query

                        Expression <Func <ESPQueryResult, bool> > icdDiseasePredicate = null;

                        foreach (var tGroup in (criteria.Criteria.SelectMany(c => c.Terms).Concat(criteria.Terms)).GroupBy(k => k.Type))
                        {
                            var termID = tGroup.Key;

                            if (termID == Lpp.QueryComposer.ModelTermsFactory.AgeRangeID)
                            {
                                selectProperties.AddRange(new[] { "Age_5yrGroup", "Age_10yrGroup" });
                                //age range is incorporated into the diagnosis and disease joins
                            }
                            else if (termID == Lpp.QueryComposer.ModelTermsFactory.ConditionsID)
                            {
                                selectProperties.AddRange(new[] { "Disease" });

                                IEnumerable <string> diseases = tGroup.Select(g => TranslateCondition(g.GetStringValue("Condition"))).ToArray();
                                if (diseases.Any())
                                {
                                    if (icdDiseasePredicate == null)
                                    {
                                        icdDiseasePredicate = q => diseases.Contains(q.Disease);
                                    }
                                    else
                                    {
                                        icdDiseasePredicate = icdDiseasePredicate.Or(q => diseases.Contains(q.Disease));
                                    }
                                }
                            }
                            else if (termID == Lpp.QueryComposer.ModelTermsFactory.EthnicityID)
                            {
                                selectProperties.Add("Ethnicity");

                                var values = tGroup.SelectMany(t => t.GetValue("Ethnicities").Values <int>()).Distinct().Select(t => TranslateEthnicity(t)).ToArray();

                                Expression <Func <ESPQueryResult, bool> > ethnicityExpression = null;
                                foreach (int value in values)
                                {
                                    if (ethnicityExpression == null)
                                    {
                                        ethnicityExpression = eth => eth.EthnicityCode == value;
                                    }
                                    else
                                    {
                                        ethnicityExpression = ethnicityExpression.Or(q => q.EthnicityCode == value);
                                    }
                                }

                                if (ethnicityExpression != null)
                                {
                                    entityQuery = entityQuery.Where(ethnicityExpression);
                                }
                            }
                            else if (termID == Lpp.QueryComposer.ModelTermsFactory.SexID)
                            {
                                selectProperties.Add("Sex");

                                IEnumerable <string> sexs = tGroup.SelectMany(t => TranslateSex(t.GetStringValue("Sex"))).Distinct();
                                logger.Debug(sexs);
                                if (sexs.Any())
                                {
                                    entityQuery = entityQuery.Where(q => sexs.Contains(q.Sex.ToUpper()));
                                }
                            }
                            else if (termID == Lpp.QueryComposer.ModelTermsFactory.ICD9DiagnosisCodes3digitID)
                            {
                                selectProperties.AddRange(new[] { "Code", "CodeDescription" });

                                //TODO:going to have to be terms for 4 and 5 digit as well.
                                IEnumerable <string> codes = tGroup.SelectMany(t => AdapterHelpers.ParseCodeTermValues(t)).Select(t => t.Trim()).Distinct();
                                if (codes.Any())
                                {
                                    Expression <Func <ESPQueryResult, bool> > icd9Expression = null;
                                    foreach (string code in codes)
                                    {
                                        if (icd9Expression == null)
                                        {
                                            icd9Expression = q => q.Code.StartsWith(code.ToUpper());
                                        }
                                        else
                                        {
                                            icd9Expression = icd9Expression.Or(q => q.Code.StartsWith(code.ToUpper()));
                                        }
                                    }

                                    if (icdDiseasePredicate == null)
                                    {
                                        icdDiseasePredicate = icd9Expression;
                                    }
                                    else
                                    {
                                        icdDiseasePredicate = icdDiseasePredicate.Or(icd9Expression);
                                    }
                                }
                            }
                            else if (termID == Lpp.QueryComposer.ModelTermsFactory.ObservationPeriodID)
                            {
                                if (hasConditionsTerm || hasICD9CodesTerm)
                                {
                                    selectProperties.AddRange(new[] { "ObservationPeriod" });
                                }
                                //observation period is incorporated into the diagnosis and disease joins
                            }
                            else if (termID == Lpp.QueryComposer.ModelTermsFactory.VisitsID)
                            {
                                try
                                {
                                    IQueryable <EncountersGroupingResult> encountersAppliedQuery = encounterQuery.GroupBy(v => new { v.PatID, v.AgeGroup5yr, v.AgeGroup10yr }).Select(v => new EncountersGroupingResult {
                                        PatID = v.Key.PatID, AgeGroup5yr = v.Key.AgeGroup5yr, AgeGroup10yr = v.Key.AgeGroup10yr, Count = v.Count()
                                    });

                                    int visits = tGroup.Where(t => t.GetValue("Visits") != null).Select(t => Convert.ToInt32(t.GetStringValue("Visits"))).Min();

                                    if (!hasConditionsTerm && !hasICD9CodesTerm)
                                    {
                                        entityQuery = entityQuery.Join(encountersAppliedQuery.Where(q => q.Count >= visits), o => o.PatientID, i => i.PatID, (o, i) => new ESPQueryResult
                                        {
                                            PatientID         = o.PatientID,
                                            Patients          = null,
                                            Sex               = o.Sex,
                                            Ethnicity         = o.Ethnicity,
                                            Race              = o.Race,
                                            Zip               = o.Zip,
                                            TobaccoUse        = o.TobaccoUse,
                                            Code              = o.Code,
                                            CodeDescription   = o.CodeDescription,
                                            Disease           = o.Disease,
                                            ObservationPeriod = o.ObservationPeriod,
                                            Age_10yrGroup     = i.AgeGroup10yr,
                                            Age_5yrGroup      = i.AgeGroup5yr,
                                            Age_Detect        = o.Age_Detect,
                                            CenterID          = o.CenterID
                                        });
                                    }
                                    else
                                    {
                                        entityQuery = entityQuery.Join(encountersAppliedQuery.Where(q => q.Count >= visits), o => o.PatientID, i => i.PatID, (o, i) => o);
                                    }
                                }
                                catch { }
                            }
                            else if (termID == Lpp.QueryComposer.ModelTermsFactory.ZipCodeID)
                            {
                                selectProperties.Add("Zip");

                                var zipCodes = tGroup.SelectMany(t => AdapterHelpers.ParseCodeTermValues(t)).Select(t => t.Trim()).Distinct();

                                if (zipCodes.Any())
                                {
                                    entityQuery = entityQuery.Where(q => zipCodes.Contains(q.Code));
                                }
                            }
                            else
                            {
                                logger.Debug("Term specified but not implemented in criteria: " + termID);
                            }
                        }

                        if (icdDiseasePredicate != null)
                        {
                            entityQuery = entityQuery.Where(icdDiseasePredicate);
                        }
                    }
                }

                entityQuery = entityQuery.GroupBy(k => new
                {
                    k.Sex,
                    k.EthnicityCode,
                    k.Ethnicity,
                    k.Race,
                    k.Zip,
                    k.TobaccoUse,
                    k.Code,
                    k.CodeDescription,
                    k.Disease,
                    k.ObservationPeriod,
                    k.Age_10yrGroup,
                    k.Age_5yrGroup,
                    k.Age_Detect,
                    k.CenterID
                })
                              .Select(k => new ESPQueryResult
                {
                    PatientID         = null,
                    Patients          = k.Count(),
                    Sex               = k.Key.Sex,
                    EthnicityCode     = k.Key.EthnicityCode,
                    Ethnicity         = k.Key.Ethnicity,
                    Race              = k.Key.Race,
                    Zip               = k.Key.Zip,
                    TobaccoUse        = k.Key.TobaccoUse,
                    Code              = k.Key.Code,
                    CodeDescription   = k.Key.CodeDescription,
                    Disease           = k.Key.Disease,
                    ObservationPeriod = k.Key.ObservationPeriod,
                    Age_10yrGroup     = k.Key.Age_10yrGroup,
                    Age_5yrGroup      = k.Key.Age_5yrGroup,
                    Age_Detect        = k.Key.Age_Detect,
                    CenterID          = k.Key.CenterID
                });



                //TODO: generate the select fields and apply to the query
                //NOTE: dynamically selecting into a result class didn't affect the generated query, skipping and filtering when building response.
                //var select = query.Select(Utility.MapToClass<ESPQueryResult, ESPAggregatedResult>(selectProperties));

                //TODO: if all projection are stratification and options specified? wrap with additional query


                //TODO: apply the ordering to the select projection

                /*
                 * Here's a possiblity using reflection...
                 *  var param = "Address";
                 *  var pi = typeof(Student).GetProperty(param);
                 *  var orderByAddress = items.OrderBy(x => pi.GetValue(x, null));
                 *
                 * see that will use expression:
                 * http://www.singingeels.com/Blogs/Nullable/2008/03/26/Dynamic_LINQ_OrderBy_using_String_Names.aspx
                 * */

                var response = new QueryComposerResponseQueryResultDTO {
                    ID = query.Header.ID, QueryStart = DateTimeOffset.UtcNow
                };
                List <Dictionary <string, object> > results = new List <Dictionary <string, object> >();
                if (!viewSQL)
                {
                    logger.Debug(entityQuery.ToString());

                    foreach (var item in entityQuery)
                    {
                        Dictionary <string, object> row = new Dictionary <string, object>();
                        Type itemType = item.GetType();
                        foreach (var propInfo in itemType.GetProperties())
                        {
                            if (selectProperties.Contains(propInfo.Name))
                            {
                                object value = propInfo.GetValue(item, null);
                                if (propInfo.Name == "ObservationPeriod")
                                {
                                    //The value is currently the number of days from Jan 1, 1960, convert to date.
                                    value = new DateTime(1960, 1, 1, 0, 0, 0, DateTimeKind.Unspecified).AddDays(Convert.ToInt32(value ?? 0));
                                }
                                row.Add(propInfo.Name, value);
                            }
                        }
                        results.Add(row);
                    }
                }
                else
                {
                    Dictionary <string, object> row = new Dictionary <string, object>();
                    row.Add("SQL", entityQuery.ToString());
                    results.Add(row);
                }

                logger.Debug("Number of results found:" + results.Count);

                //QueryComposerResponseDTO response = new QueryComposerResponseDTO
                //{
                //    ResponseDateTime = DateTime.UtcNow,
                //    Results = new[] { results }
                //};

                //if (query.ID.HasValue)
                //    response.RequestID = query.ID.Value;

                response.QueryEnd = DateTimeOffset.UtcNow;
                response.Results  = new[] { results };

                return(new[] { response });
            }
        }
        public override IEnumerable <System.Linq.Expressions.MemberBinding> InnerSelectBindings(Type selectType, System.Linq.Expressions.ParameterExpression sourceTypeParameter)
        {
            ParameterExpression pe_sourceQueryType = sourceTypeParameter;
            ParameterExpression pe_vitalsQueryType = Expression.Parameter(typeof(PCORIQueryBuilder.Model.Vital), "v");
            Expression          measuredOnSelector = Expression.Property(pe_vitalsQueryType, "MeasuredOn");

            BinaryExpression be_vitalsPatient = Expression.Equal(Expression.Property(pe_vitalsQueryType, "PatientID"), Expression.Property(pe_sourceQueryType, "ID"));

            //apply all the applicable criteria to the inner value select as well.
            List <Expression> predicates = new List <Expression>();

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.ObservationPeriodID) || c.Criteria.Any(ci => ci.Terms.Any(t => t.Type == ModelTermsFactory.ObservationPeriodID))))
            {
                Expression prop_Encounter = Expression.Property(pe_vitalsQueryType, "Encounter");
                Expression proper_Encounter_AdmittedOn = Expression.Property(prop_Encounter, "AdmittedOn");

                BinaryExpression observationPeriodPredicate = null;

                var observationPeriodCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.ObservationPeriodID)).Union(Criteria.SelectMany(c => c.Criteria.SelectMany(ci => ci.Terms.Where(t => t.Type == ModelTermsFactory.ObservationPeriodID))));
                foreach (var obpTerm in observationPeriodCriteria)
                {
                    BinaryExpression obp_predicate = null;
                    var obp_values = AdapterHelpers.ParseDateRangeValues(obpTerm);
                    if (obp_values.StartDate.HasValue && obp_values.EndDate.HasValue)
                    {
                        DateTime startDate = obp_values.StartDate.Value.Date;
                        DateTime endDate   = obp_values.EndDate.Value.Date;
                        obp_predicate = Expression.AndAlso(Expression.GreaterThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(startDate)), Expression.LessThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(endDate)));
                    }
                    else if (obp_values.StartDate.HasValue)
                    {
                        DateTime startDate = obp_values.StartDate.Value.Date;
                        obp_predicate = Expression.GreaterThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(startDate));
                    }
                    else if (obp_values.EndDate.HasValue)
                    {
                        DateTime endDate = obp_values.EndDate.Value.Date;
                        obp_predicate = Expression.LessThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(endDate));
                    }

                    if (obp_predicate == null)
                    {
                        continue;
                    }

                    if (observationPeriodPredicate == null)
                    {
                        observationPeriodPredicate = Expression.AndAlso(Expression.NotEqual(Expression.Property(pe_vitalsQueryType, "EncounterID"), Expression.Constant(null)), obp_predicate);
                    }
                    else
                    {
                        observationPeriodPredicate = Expression.AndAlso(observationPeriodPredicate, obp_predicate);
                    }
                }

                if (observationPeriodPredicate != null)
                {
                    predicates.Add(observationPeriodPredicate);
                }
            }

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.HeightID) || c.Criteria.Any(ci => ci.Terms.Any(t => t.Type == ModelTermsFactory.HeightID))))
            {
                Expression heightExp = Expression.Property(pe_vitalsQueryType, "Height");
                predicates.Add(Expression.Equal(Expression.Property(heightExp, "HasValue"), Expression.Constant(true)));

                Expression heightSelector = Expression.Property(heightExp, "Value");

                var heightCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.HeightID)).Union(Criteria.SelectMany(c => c.Criteria.SelectMany(ci => ci.Terms.Where(t => t.Type == ModelTermsFactory.HeightID))));
                foreach (var heightTerm in heightCriteria)
                {
                    var heightRange = AdapterHelpers.ParseHeightValues(heightTerm);
                    if (heightRange.MinHeight.HasValue)
                    {
                        double minHeight = heightRange.MinHeight.Value;
                        predicates.Add(
                            Expression.GreaterThanOrEqual(heightSelector, Expression.Constant(minHeight))
                            );
                    }
                    if (heightRange.MaxHeight.HasValue)
                    {
                        double maxHeight = heightRange.MaxHeight.Value;
                        predicates.Add(
                            Expression.LessThanOrEqual(heightSelector, Expression.Constant(maxHeight))
                            );
                    }
                }
            }

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.WeightID) || c.Criteria.Any(ci => ci.Terms.Any(t => t.Type == ModelTermsFactory.WeightID))))
            {
                Expression weightExp = Expression.Property(pe_vitalsQueryType, "Weight");
                predicates.Add(Expression.Equal(Expression.Property(weightExp, "HasValue"), Expression.Constant(true)));

                Expression weightSelector = Expression.Property(weightExp, "Value");

                var weightCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.WeightID)).Union(Criteria.SelectMany(c => c.Criteria.SelectMany(ci => ci.Terms.Where(t => t.Type == ModelTermsFactory.WeightID))));
                foreach (var weightTerm in weightCriteria)
                {
                    var weightRange = AdapterHelpers.ParseWeightValues(weightTerm);
                    if (weightRange.MinWeight.HasValue)
                    {
                        double minWeight = weightRange.MinWeight.Value;
                        predicates.Add(
                            Expression.GreaterThanOrEqual(weightSelector, Expression.Constant(minWeight))
                            );
                    }
                    if (weightRange.MaxWeight.HasValue)
                    {
                        double maxWeight = weightRange.MaxWeight.Value;
                        predicates.Add(
                            Expression.LessThanOrEqual(weightSelector, Expression.Constant(maxWeight))
                            );
                    }
                }
            }

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.VitalsMeasureDateID) || c.Criteria.Any(ci => ci.Terms.Any(t => t.Type == ModelTermsFactory.VitalsMeasureDateID))))
            {
                var measureDateCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.VitalsMeasureDateID)).Union(Criteria.SelectMany(c => c.Criteria.SelectMany(ci => ci.Terms.Where(t => t.Type == ModelTermsFactory.VitalsMeasureDateID))));
                foreach (var measureDateTerm in measureDateCriteria)
                {
                    BinaryExpression md_predicate = null;
                    var md_values = AdapterHelpers.ParseDateRangeValues(measureDateTerm);
                    if (md_values.StartDate.HasValue && md_values.EndDate.HasValue)
                    {
                        DateTime startDate = md_values.StartDate.Value.Date;
                        DateTime endDate   = md_values.EndDate.Value.Date;
                        md_predicate = Expression.AndAlso(Expression.GreaterThanOrEqual(measuredOnSelector, Expression.Constant(startDate)), Expression.LessThanOrEqual(measuredOnSelector, Expression.Constant(endDate)));
                    }
                    else if (md_values.StartDate.HasValue)
                    {
                        DateTime startDate = md_values.StartDate.Value.Date;
                        md_predicate = Expression.GreaterThanOrEqual(measuredOnSelector, Expression.Constant(startDate));
                    }
                    else if (md_values.EndDate.HasValue)
                    {
                        DateTime endDate = md_values.EndDate.Value.Date;
                        md_predicate = Expression.LessThanOrEqual(measuredOnSelector, Expression.Constant(endDate));
                    }

                    if (md_predicate != null)
                    {
                        predicates.Add(md_predicate);
                    }
                }
            }

            Expression predicateExpression;

            if (predicates.Count == 0)
            {
                predicateExpression = be_vitalsPatient;
            }
            else
            {
                predicateExpression = Expression.AndAlso(be_vitalsPatient, predicates[0]);
                if (predicates.Count > 1)
                {
                    for (int i = 1; i < predicates.Count; i++)
                    {
                        predicateExpression = Expression.AndAlso(predicateExpression, predicates[i]);
                    }
                }
            }

            Expression           vitalsProp      = Expressions.AsQueryable(Expression.Property(sourceTypeParameter, "Vitals"));
            MethodCallExpression measuredOnWhere = Expressions.Where(vitalsProp, Expression.Lambda(predicateExpression, pe_vitalsQueryType));

            MethodCallExpression orderByMeasureOn = Expressions.OrderByAscending(measuredOnWhere, Expression.Lambda(measuredOnSelector, pe_vitalsQueryType));

            MethodCallExpression measureOnSelect = Expression.Call(typeof(Queryable), "Select", new Type[] { pe_vitalsQueryType.Type, measuredOnSelector.Type }, orderByMeasureOn, Expression.Quote(Expression.Lambda(measuredOnSelector, pe_vitalsQueryType)));

            MethodCallExpression firstOrDefaultVitalMeasuredOn = Expression.Call(typeof(Queryable), "FirstOrDefault", new Type[] { typeof(DateTime) }, measureOnSelect);

            return(new[] {
                Expression.Bind(selectType.GetProperty("MeasuredOn"), firstOrDefaultVitalMeasuredOn)
            });
        }
示例#4
0
        public override IEnumerable <System.Linq.Expressions.MemberBinding> InnerSelectBindings(Type selectType, System.Linq.Expressions.ParameterExpression sourceTypeParameter)
        {
            //the earliest  encounter date that satisfies the query critieria

            ParameterExpression pe_sourceQueryType = sourceTypeParameter;

            Expression encountersProp = Expressions.AsQueryable(Expression.Property(pe_sourceQueryType, "Encounters"));

            ParameterExpression pe_encountersQueryType = Expression.Parameter(typeof(PCORIQueryBuilder.Model.Encounter), "enc");

            Expression admittedOnSelector = Expression.Property(pe_encountersQueryType, "AdmittedOn");

            Expression encounterTypeSelector = Expression.Property(pe_encountersQueryType, "EncounterType");

            BinaryExpression be_encounterPatient = Expression.Equal(Expression.Property(pe_sourceQueryType, "ID"), Expression.Property(pe_encountersQueryType, "PatientID"));

            BinaryExpression predicate = be_encounterPatient;

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.ObservationPeriodID) || c.Criteria.Any(ci => ci.Terms.Any(t => t.Type == ModelTermsFactory.ObservationPeriodID))))
            {
                var observationPeriodCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.ObservationPeriodID)).Union(Criteria.SelectMany(c => c.Criteria.SelectMany(ci => ci.Terms.Where(t => t.Type == ModelTermsFactory.ObservationPeriodID))));
                foreach (var obpTerm in observationPeriodCriteria)
                {
                    var range = AdapterHelpers.ParseDateRangeValues(obpTerm);
                    if (range.StartDate.HasValue)
                    {
                        predicate = Expression.AndAlso(predicate, Expression.GreaterThanOrEqual(admittedOnSelector, Expression.Constant(range.StartDate.Value.DateTime.Date)));
                    }
                    if (range.EndDate.HasValue)
                    {
                        predicate = Expression.AndAlso(predicate, Expression.LessThanOrEqual(admittedOnSelector, Expression.Constant(range.EndDate.Value.DateTime.Date)));
                    }
                }
            }

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.SettingID) || c.Criteria.Any(ci => ci.Terms.Any(t => t.Type == ModelTermsFactory.SettingID))))
            {
                var settingCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.SettingID)).Union(Criteria.SelectMany(c => c.Criteria.SelectMany(ci => ci.Terms.Where(t => t.Type == ModelTermsFactory.SettingID))));;
                foreach (var term in settingCriteria)
                {
                    string             value = term.GetStringValue("Setting");
                    DTO.Enums.Settings enumValue;
                    if (Enum.TryParse <DTO.Enums.Settings>(value, out enumValue))
                    {
                        value = enumValue.ToString("G");
                    }

                    if (enumValue == DTO.Enums.Settings.AN)
                    {
                        //any encounter setting that is not null or string.Empty.
                        predicate = Expression.AndAlso(predicate, Expression.AndAlso(Expression.NotEqual(encounterTypeSelector, Expression.Constant("", typeof(string))), Expression.NotEqual(encounterTypeSelector, Expression.Constant(null))));
                    }
                    else if (!string.IsNullOrEmpty(value))
                    {
                        predicate = Expression.AndAlso(predicate, Expression.Equal(encounterTypeSelector, Expression.Constant(value, typeof(string))));
                    }
                }
            }

            MethodCallExpression encounterTypeWhere = Expressions.Where(encountersProp, Expression.Lambda(predicate, pe_encountersQueryType));

            MethodCallExpression orderByAdmittedOn = Expressions.OrderByAscending(encounterTypeWhere, Expression.Lambda(admittedOnSelector, pe_encountersQueryType));

            MethodCallExpression encounterTypeSelect = Expressions.Select(pe_encountersQueryType.Type, encounterTypeSelector.Type, orderByAdmittedOn, Expression.Lambda(encounterTypeSelector, pe_encountersQueryType));

            MethodCallExpression firstOrDefaultEncounterType = Expressions.FirstOrDefault <string>(encounterTypeSelect);

            return(new[] {
                Expression.Bind(selectType.GetProperty("EncounterType"), firstOrDefaultEncounterType)
            });
        }
示例#5
0
        public override IEnumerable <System.Linq.Expressions.MemberBinding> InnerSelectBindings(Type selectType, System.Linq.Expressions.ParameterExpression sourceTypeParameter)
        {
            ParameterExpression pe_sourceQueryType   = sourceTypeParameter;
            ParameterExpression pe_vitalsQueryType   = Expression.Parameter(typeof(PCORIQueryBuilder.Model.Vital), "v");
            Expression          weightSelector       = Expression.Property(pe_vitalsQueryType, "Weight");
            Expression          weightSelector_Value = Expression.Property(Expression.Property(pe_vitalsQueryType, "Weight"), "Value");

            BinaryExpression be_vitalsPatient = Expression.Equal(Expression.Property(pe_vitalsQueryType, "PatientID"), Expression.Property(pe_sourceQueryType, "ID"));

            //apply all the applicable criteria to the inner value select as well.
            List <Expression> predicates = new List <Expression>();

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.ObservationPeriodID)))
            {
                Expression prop_Encounter = Expression.Property(pe_vitalsQueryType, "Encounter");
                Expression proper_Encounter_AdmittedOn = Expression.Property(prop_Encounter, "AdmittedOn");

                BinaryExpression observationPeriodPredicate = null;

                var observationPeriodCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.ObservationPeriodID));
                foreach (var obpTerm in observationPeriodCriteria)
                {
                    BinaryExpression obp_predicate = null;
                    var obp_values = AdapterHelpers.ParseDateRangeValues(obpTerm);
                    if (obp_values.StartDate.HasValue && obp_values.EndDate.HasValue)
                    {
                        DateTime startDate = obp_values.StartDate.Value.Date;
                        DateTime endDate   = obp_values.EndDate.Value.Date;
                        obp_predicate = Expression.AndAlso(Expression.GreaterThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(startDate)), Expression.LessThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(endDate)));
                    }
                    else if (obp_values.StartDate.HasValue)
                    {
                        DateTime startDate = obp_values.StartDate.Value.Date;
                        obp_predicate = Expression.GreaterThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(startDate));
                    }
                    else if (obp_values.EndDate.HasValue)
                    {
                        DateTime endDate = obp_values.EndDate.Value.Date;
                        obp_predicate = Expression.LessThanOrEqual(proper_Encounter_AdmittedOn, Expression.Constant(endDate));
                    }

                    if (obp_predicate == null)
                    {
                        continue;
                    }

                    if (observationPeriodPredicate == null)
                    {
                        observationPeriodPredicate = Expression.AndAlso(Expression.NotEqual(Expression.Property(pe_vitalsQueryType, "EncounterID"), Expression.Constant(null)), obp_predicate);
                    }
                    else
                    {
                        observationPeriodPredicate = Expression.AndAlso(observationPeriodPredicate, obp_predicate);
                    }
                }

                if (observationPeriodPredicate != null)
                {
                    predicates.Add(observationPeriodPredicate);
                }
            }


            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.HeightID)))
            {
                Expression heightSelector = Expression.Property(pe_vitalsQueryType, "Height");
                predicates.Add(Expression.Equal(Expression.Property(heightSelector, "HasValue"), Expression.Constant(true)));

                Expression heightSelector_Value = Expression.Property(heightSelector, "Value");

                var heightCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.HeightID));
                foreach (var heightTerm in heightCriteria)
                {
                    var heightRange = AdapterHelpers.ParseHeightValues(heightTerm);
                    if (heightRange.MinHeight.HasValue)
                    {
                        double minHeight = heightRange.MinHeight.Value;
                        predicates.Add(
                            Expression.GreaterThanOrEqual(heightSelector_Value, Expression.Constant(minHeight))
                            );
                    }
                    if (heightRange.MaxHeight.HasValue)
                    {
                        double maxHeight = heightRange.MaxHeight.Value;
                        predicates.Add(
                            Expression.LessThanOrEqual(heightSelector_Value, Expression.Constant(maxHeight))
                            );
                    }
                }
            }

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.WeightID)))
            {
                //if the weight term is included in critieria it enforces that the weight value cannot be null
                predicates.Add(Expression.Equal(Expression.Property(weightSelector, "HasValue"), Expression.Constant(true)));

                var weightCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.WeightID));
                foreach (var weightTerm in weightCriteria)
                {
                    var weightRange = AdapterHelpers.ParseWeightValues(weightTerm);
                    if (weightRange.MinWeight.HasValue)
                    {
                        double minWeight = weightRange.MinWeight.Value;
                        predicates.Add(
                            Expression.GreaterThanOrEqual(weightSelector_Value, Expression.Constant(minWeight))
                            );
                    }
                    if (weightRange.MaxWeight.HasValue)
                    {
                        double maxWeight = weightRange.MaxWeight.Value;
                        predicates.Add(
                            Expression.LessThanOrEqual(weightSelector_Value, Expression.Constant(maxWeight))
                            );
                    }
                }
            }

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.VitalsMeasureDateID)))
            {
                Expression measuredOnSelector = Expression.Property(pe_vitalsQueryType, "MeasuredOn");

                var measureDateCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.VitalsMeasureDateID));
                foreach (var measureDateTerm in measureDateCriteria)
                {
                    BinaryExpression md_predicate = null;
                    var md_values = AdapterHelpers.ParseDateRangeValues(measureDateTerm);
                    if (md_values.StartDate.HasValue && md_values.EndDate.HasValue)
                    {
                        DateTime startDate = md_values.StartDate.Value.Date;
                        DateTime endDate   = md_values.EndDate.Value.Date;
                        md_predicate = Expression.AndAlso(Expression.GreaterThanOrEqual(measuredOnSelector, Expression.Constant(startDate)), Expression.LessThanOrEqual(measuredOnSelector, Expression.Constant(endDate)));
                    }
                    else if (md_values.StartDate.HasValue)
                    {
                        DateTime startDate = md_values.StartDate.Value.Date;
                        md_predicate = Expression.GreaterThanOrEqual(measuredOnSelector, Expression.Constant(startDate));
                    }
                    else if (md_values.EndDate.HasValue)
                    {
                        DateTime endDate = md_values.EndDate.Value.Date;
                        md_predicate = Expression.LessThanOrEqual(measuredOnSelector, Expression.Constant(endDate));
                    }

                    if (md_predicate != null)
                    {
                        predicates.Add(md_predicate);
                    }
                }
            }

            Expression predicateExpression = null;

            if (predicates.Count > 0)
            {
                predicateExpression = predicates[0];
                if (predicates.Count > 1)
                {
                    for (int i = 1; i < predicates.Count; i++)
                    {
                        predicateExpression = Expression.AndAlso(predicateExpression, predicates[i]);
                    }
                }
            }

            Expression vitalsProp = Expressions.AsQueryable(Expression.Property(sourceTypeParameter, "Vitals"));

            Expression           measureOnSelector = Expression.Property(pe_vitalsQueryType, "MeasuredOn");
            MethodCallExpression orderByMeasureOn;

            if (predicateExpression == null)
            {
                orderByMeasureOn = Expressions.OrderByAscending(vitalsProp, Expression.Lambda(measureOnSelector, pe_vitalsQueryType));
            }
            else
            {
                MethodCallExpression weightWhere = Expressions.Where(vitalsProp, Expression.Lambda(predicateExpression, pe_vitalsQueryType));
                orderByMeasureOn = Expressions.OrderByAscending(weightWhere, Expression.Lambda(measureOnSelector, pe_vitalsQueryType));
            }

            MethodCallExpression weightSelect = Expressions.Select(pe_vitalsQueryType.Type, weightSelector.Type, orderByMeasureOn, Expression.Lambda(weightSelector, pe_vitalsQueryType));

            MethodCallExpression firstOrDefaultVitalWeight = Expressions.FirstOrDefault <double?>(weightSelect);

            if (!HasStratifications)
            {
                return(new[] {
                    Expression.Bind(selectType.GetProperty("Weight"), firstOrDefaultVitalWeight)
                });
            }

            // apply the modifier for stratification
            DTO.Enums.WeightStratification stratification;
            if (!Enum.TryParse <DTO.Enums.WeightStratification>(Stratifications.First().ToString(), out stratification))
            {
                throw new ArgumentException("Unable to parse the specified stratification value as an WeightStratification: " + Stratifications.First().ToString());
            }

            Expression stratificationExp = Expression.Condition(Expression.Equal(Expression.Property(firstOrDefaultVitalWeight, "HasValue"), Expression.Constant(true, typeof(bool))),
                                                                Expression.Convert(Expressions.MathFloor <double>(Expression.Divide(Expression.Property(firstOrDefaultVitalWeight, "Value"), Expression.Constant(Convert.ToDouble((int)stratification)))), typeof(double?)),
                                                                firstOrDefaultVitalWeight);

            return(new[] {
                Expression.Bind(selectType.GetProperty("Weight"), stratificationExp)
            });
        }
        public override IEnumerable <System.Linq.Expressions.MemberBinding> InnerSelectBindings(Type selectType, System.Linq.Expressions.ParameterExpression sourceTypeParameter)
        {
            //the earliest  encounter date that satisfies the query critieria

            ParameterExpression pe_sourceQueryType = sourceTypeParameter;

            Expression encountersProp = Expressions.AsQueryable(Expression.Property(pe_sourceQueryType, "Encounters"));

            ParameterExpression pe_encountersQueryType = Expression.Parameter(typeof(PCORIQueryBuilder.Model.Encounter), "enc");

            Expression admittedOnSelector = Expression.Property(pe_encountersQueryType, "AdmittedOn");

            BinaryExpression be_encounterPatient = Expression.Equal(Expression.Property(pe_sourceQueryType, "ID"), Expression.Property(pe_encountersQueryType, "PatientID"));

            BinaryExpression predicate = be_encounterPatient;

            if (Criteria.Any(c => c.Terms.Any(t => t.Type == ModelTermsFactory.ObservationPeriodID)))
            {
                var observationPeriodCriteria = Criteria.SelectMany(c => c.Terms.Where(t => t.Type == ModelTermsFactory.ObservationPeriodID));
                foreach (var obpTerm in observationPeriodCriteria)
                {
                    DateTime dateValue;
                    var      range = AdapterHelpers.ParseDateRangeValues(obpTerm);
                    if (range.StartDate.HasValue)
                    {
                        dateValue = range.StartDate.Value.DateTime.Date;
                        predicate = Expression.AndAlso(predicate, Expression.GreaterThanOrEqual(admittedOnSelector, Expression.Constant(dateValue)));
                    }
                    if (range.EndDate.HasValue)
                    {
                        dateValue = range.EndDate.Value.DateTime.Date;
                        predicate = Expression.AndAlso(predicate, Expression.LessThanOrEqual(admittedOnSelector, Expression.Constant(dateValue)));
                    }
                }
            }

            MethodCallExpression admittedOnWhere = Expressions.Where(encountersProp, Expression.Lambda(predicate, pe_encountersQueryType));

            MethodCallExpression orderByAdmittedOn = Expressions.OrderByAscending(admittedOnWhere, Expression.Lambda(admittedOnSelector, pe_encountersQueryType));

            //need to cast the return type of the select to a nullable datetime so that the FirstOrDefault will be null as the default
            MethodCallExpression admittedOnSelect = Expressions.Select(pe_encountersQueryType.Type, typeof(DateTime?), orderByAdmittedOn, Expression.Lambda(Expression.Convert(admittedOnSelector, typeof(DateTime?)), pe_encountersQueryType));

            MethodCallExpression firstOrDefaultAdmittedOn = Expressions.FirstOrDefault <DateTime?>(admittedOnSelect);

            if (!HasStratifications)
            {
                return(new[] {
                    Expression.Bind(selectType.GetProperty("AdmittedOn"), firstOrDefaultAdmittedOn)
                });
            }

            //if stratified by Month -> return as string in format yyyy-MM
            //if stratified by Year -> return as string in format yyyy

            DTO.Enums.PeriodStratification stratification;
            if (!Enum.TryParse <DTO.Enums.PeriodStratification>(Stratifications.First().ToString(), out stratification))
            {
                throw new ArgumentException("Unable to parse the specified stratification value as an PeriodStratification: " + Stratifications.First().ToString());
            }

            Expression prop = Expression.Property(firstOrDefaultAdmittedOn, "Value");
            //Expression yearPartString = Expressions.CallToString<int>(Expression.Property(prop, "Year"));
            //if (stratification == DTO.Enums.PeriodStratification.Monthly)
            //{
            //    //if stratified by Month -> return as string in format yyyy-MM
            //    Expression monthPartString = Expressions.CallToString<int>(Expression.Property(prop, "Month"));

            //    prop = Expressions.ConcatStrings(yearPartString, Expression.Constant("-"), monthPartString);
            //}
            //else if (stratification == DTO.Enums.PeriodStratification.Yearly)
            //{
            //    //if stratified by Year -> return as string in format yyyy
            //    prop = yearPartString;
            //}
            //else
            //{
            //    throw new NotSupportedException("The specified period stratifcation is not currently supported; stratification value: " + Stratifications.First().ToString());
            //}

            //Expression stratificationModifier = Expression.Condition(Expression.NotEqual(firstOrDefaultAdmittedOn, Expression.Constant(null)), prop, Expression.Constant("", typeof(string)));
            //return new[] {
            //        Expression.Bind(selectType.GetProperty("AdmittedOn"), stratificationModifier)
            //    };

            Expression yearProp  = Expression.Property(prop, "Year");
            Expression monthProp = Expression.Property(prop, "Month");

            return(new[] {
                Expression.Bind(selectType.GetProperty("AdmittedOn"), firstOrDefaultAdmittedOn),
                Expression.Bind(selectType.GetProperty("AdmittedOnYear"), yearProp),
                Expression.Bind(selectType.GetProperty("AdmittedOnMonth"), monthProp)
            });
        }