/// <summary> /// Binds the attendees grid. /// </summary> private void BindGiversGrid() { // Get all the selected criteria values var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( drpSlidingDateRange.DelimitedValues ); var start = dateRange.Start; var end = dateRange.End; var minAmount = nreAmount.LowerValue; var maxAmount = nreAmount.UpperValue; var currencyTypeIds = new List<int>(); cblCurrencyTypes.SelectedValues.ForEach( i => currencyTypeIds.Add( i.AsInteger() ) ); var sourceTypeIds = new List<int>(); cblTransactionSource.SelectedValues.ForEach( i => sourceTypeIds.Add( i.AsInteger() ) ); var accountIds = new List<int>(); foreach ( var cblAccounts in phAccounts.Controls.OfType<RockCheckBoxList>() ) { accountIds.AddRange( cblAccounts.SelectedValuesAsInt ); } var dataViewId = dvpDataView.SelectedValueAsInt(); GiversViewBy viewBy = GiversViewBy.Giver; if ( !HideViewByOption ) { viewBy = hfViewBy.Value.ConvertToEnumOrNull<GiversViewBy>() ?? GiversViewBy.Giver; } // Clear all the existing grid columns var selectField = new SelectField(); var oldSelectField = gGiversGifts.ColumnsOfType<SelectField>().FirstOrDefault(); if (oldSelectField != null ) { selectField.SelectedKeys.AddRange( oldSelectField.SelectedKeys ); } gGiversGifts.Columns.Clear(); // Add a column for selecting rows gGiversGifts.Columns.Add( selectField ); // Add a column for the person's name gGiversGifts.Columns.Add( new RockBoundField { DataField = "PersonName", HeaderText = "Person", SortExpression = "LastName,NickName" } ); // add a column for email (but is only included on excel export) gGiversGifts.Columns.Add( new RockBoundField { DataField = "Email", HeaderText = "Email", SortExpression = "Email", Visible = false, ExcelExportBehavior = ExcelExportBehavior.AlwaysInclude } ); // Add a column for total amount gGiversGifts.Columns.Add( new CurrencyField { DataField = "TotalAmount", HeaderText = "Total", SortExpression = "TotalAmount" } ); // Add columns for the selected account totals if ( accountIds.Any() ) { var accounts = new FinancialAccountService( _rockContext ) .Queryable().AsNoTracking() .Where( a => accountIds.Contains( a.Id ) ) .ToList(); foreach ( int accountId in accountIds ) { var account = accounts.FirstOrDefault( a => a.Id == accountId ); if ( account != null ) { gGiversGifts.Columns.Add( new CurrencyField { DataField = account.Id.ToString(), HeaderText = account.Name, SortExpression = account.Id.ToString() } ); } } } // Add a column for the number of gifts var numberGiftsField = new RockBoundField { DataField = "NumberGifts", HeaderText = "Number of Gifts", SortExpression = "NumberGifts", DataFormatString = "{0:N0}", }; numberGiftsField.ItemStyle.HorizontalAlign = HorizontalAlign.Right; gGiversGifts.Columns.Add( numberGiftsField ); // Add a column to indicate if this is a first time giver gGiversGifts.Columns.Add( new BoolField { DataField = "IsFirstEverGift", HeaderText = "Is First Gift", SortExpression = "IsFirstEverGift" } ); // Add a column for the first gift date ( that matches criteria ) gGiversGifts.Columns.Add( new DateField { DataField = "FirstGift", HeaderText = "First Gift", SortExpression = "FirstGift" } ); // Add a column for the first-ever gift date ( to any tax-deductible account ) gGiversGifts.Columns.Add( new DateField { DataField = "FirstEverGift", HeaderText = "First Gift Ever", SortExpression = "FirstEverGift" } ); var transactionDetailService = new FinancialTransactionDetailService( _rockContext ); var personService = new PersonService( _rockContext ); // If dataview was selected get the person id's returned by the dataview var dataViewPersonIds = new List<int>(); if ( dataViewId.HasValue ) { var dataView = new DataViewService( _rockContext ).Get( dataViewId.Value ); if ( dataView != null ) { var errorMessages = new List<string>(); ParameterExpression paramExpression = personService.ParameterExpression; Expression whereExpression = dataView.GetExpression( personService, paramExpression, out errorMessages ); SortProperty sortProperty = null; var dataViewPersonIdQry = personService .Queryable().AsNoTracking() .Where( paramExpression, whereExpression, sortProperty ) .Select( p => p.Id ); dataViewPersonIds = dataViewPersonIdQry.ToList(); } } // Check to see if grid should display only people who gave a certain number of times and if so // set the min value int minCount = 0; var previousPersonIds = new List<int>(); if ( radByPattern.Checked ) { minCount = tbPatternXTimes.Text.AsInteger(); var missedStart = drpPatternDateRange.LowerValue; var missedEnd = drpPatternDateRange.UpperValue; if ( missedStart.HasValue && missedEnd.HasValue ) { // Get the givingids that gave any amount during the pattern's date range. These // are needed so that we know who to exclude from the result set var previousGivingIds = transactionDetailService .Queryable().AsNoTracking() .Where( d => d.Transaction.TransactionDateTime.HasValue && d.Transaction.TransactionDateTime.Value >= missedStart.Value && d.Transaction.TransactionDateTime.Value < missedEnd.Value && accountIds.Contains( d.AccountId ) && d.Amount != 0.0M ) .Select( d => d.Transaction.AuthorizedPersonAlias.Person.GivingId ); // Now get the person ids from the givingids previousPersonIds = personService .Queryable().AsNoTracking() .Where( p => previousGivingIds.Contains( p.GivingId ) ) .Select( p => p.Id ) .ToList(); } } // Call the stored procedure to get all the giving data that matches the selected criteria. // The stored procedure returns two tables. First is a list of all matching transaction summary // information and the second table is each giving leader's first-ever gift date to a tax-deductible account DataSet ds = FinancialTransactionDetailService.GetGivingAnalytics( start, end, minAmount, maxAmount, accountIds, currencyTypeIds, sourceTypeIds, dataViewId, viewBy ); // Get the results table DataTable dtResults = ds.Tables[0]; // Get the first-ever gift dates and load them into a dictionary for faster matching DataTable dtFirstEver = ds.Tables[1]; var firstEverVals = new Dictionary<int, DateTime>(); foreach( DataRow row in ds.Tables[1].Rows ) { if ( !DBNull.Value.Equals( row["FirstEverGift"] ) ) { firstEverVals.Add( (int)row["PersonId"], (DateTime)row["FirstEverGift"] ); } } // Add columns to the result set for the first-ever data dtResults.Columns.Add( new DataColumn( "IsFirstEverGift", typeof( bool ) ) ); dtResults.Columns.Add( new DataColumn( "FirstEverGift", typeof( DateTime ) ) ); foreach( DataRow row in dtResults.Rows ) { bool rowValid = true; // Get the person id int personId = (int)row["Id"]; if ( radByPattern.Checked ) { // If pattern was specified check minimum gifts and other date range int numberGifts = (int)row["NumberGifts"]; if ( numberGifts < minCount ) { rowValid = false; } else { // If this giving leader gave during the pattern date, remove the row since we // only want those who did not if ( previousPersonIds.Contains( personId ) ) { rowValid = false; } } } if ( dataViewId.HasValue ) { // If a dataview filter was specified, and this row is not part of dataview, // remove it if ( !dataViewPersonIds.Contains(personId)) { rowValid = false; // Remove person id from list so that list can be used later to optionally // add rows for remaining people who were in the dataview, but not in the // result set dataViewPersonIds.Remove( personId ); } } if ( rowValid ) { // Set the first ever information for each row bool isFirstEverGift = false; DateTime firstGift = (DateTime)row["FirstGift"]; if ( firstEverVals.ContainsKey( personId ) ) { DateTime firstEverGift = firstEverVals[personId]; isFirstEverGift = firstEverGift.Equals( firstGift ); row["FirstEverGift"] = firstEverGift; } // If only first time givers should be included, remove any that are not if ( radFirstTime.Checked && !isFirstEverGift ) { rowValid = false; } else { row["IsFirstEverGift"] = isFirstEverGift; } } if ( !rowValid ) { row.Delete(); } } // if dataview was selected and it includes people not in the result set, if ( dataViewId.HasValue && rblDataViewAction.SelectedValue == "All" && dataViewPersonIds.Any() ) { // Query for the names of each of these people foreach( var person in personService .Queryable().AsNoTracking() .Select( p => new { p.Id, p.Guid, p.NickName, p.LastName, p.Email })) { // Check for a first ever gift date var firstEverGiftDate = firstEverVals .Where( f => f.Key == person.Id ) .Select( f => f.Value ) .FirstOrDefault(); DataRow row = dtResults.NewRow(); row["Id"] = person.Id; row["Guid"] = person.Guid; row["NickName"] = person.NickName; row["LastName"] = person.LastName; row["PersonName"] = person.NickName + " " + person.LastName; row["Email"] = person.Email; row["IsFirstEverGift"] = false; row["FirstEverGift"] = firstEverGiftDate; dtResults.Rows.Add( row ); } } // Update the changes (deletes) in the datatable dtResults.AcceptChanges(); // Calculate Total if ( viewBy == GiversViewBy.Giver ) { pnlTotal.Visible = true; object amountTotalObj = dtResults.Compute( "Sum(TotalAmount)", null ); if ( amountTotalObj != null ) { decimal amountTotal = amountTotalObj.ToString().AsDecimal(); lTotal.Text = amountTotal.FormatAsCurrency(); } else { lTotal.Text = string.Empty; } } else { pnlTotal.Visible = false; } // Sort the results System.Data.DataView dv = dtResults.DefaultView; if ( gGiversGifts.SortProperty != null ) { try { var sortProperties = new List<string>(); foreach( string prop in gGiversGifts.SortProperty.Property.SplitDelimitedValues(false)) { sortProperties.Add( string.Format( "[{0}] {1}", prop, gGiversGifts.SortProperty.DirectionString ) ); } dv.Sort = sortProperties.AsDelimited( ", " ); } catch { dv.Sort = "[LastName] ASC, [NickName] ASC"; } } else { dv.Sort = "[LastName] ASC, [NickName] ASC"; } gGiversGifts.DataSource = dv; gGiversGifts.DataBind(); }
/// <summary> /// Gets the preview columns. /// </summary> /// <param name="modelType">Type of the model.</param> /// <returns></returns> public List<DataControlField> GetPreviewColumns( Type modelType ) { var displayColumns = new List<DataControlField>(); var allColumns = new List<DataControlField>(); // If displaying people, add select field (for merging & communication) if ( !string.IsNullOrWhiteSpace( PersonIdField ) ) { var selectField = new SelectField(); displayColumns.Add( selectField ); allColumns.Add( selectField ); } foreach ( var property in modelType.GetProperties() ) { // limit to non-virtual methods to prevent lazy loading issues var getMethod = property.GetGetMethod(); if ( !getMethod.IsVirtual ) { if ( property.Name != "Id" ) { BoundField boundField = GetGridField( property.PropertyType ); boundField.DataField = property.Name; boundField.SortExpression = property.Name; boundField.HeaderText = property.Name.SplitCase(); if ( property.GetCustomAttributes( typeof( Rock.Data.PreviewableAttribute ) ).Count() > 0 ) { displayColumns.Add( boundField ); } else if ( displayColumns.Count == 0 && property.GetCustomAttributes( typeof( System.Runtime.Serialization.DataMemberAttribute ) ).Count() > 0 && !property.GetCustomAttributes( typeof( HideFromReportingAttribute ), true ).Any() ) { allColumns.Add( boundField ); } } } } var columns = new List<DataControlField>(); // Always add hidden id column var idCol = new BoundField(); idCol.DataField = "Id"; idCol.Visible = false; columns.Add( idCol ); columns.AddRange( displayColumns.Count > 0 ? displayColumns : allColumns ); return columns; }
/// <summary> /// Binds the attendees grid. /// </summary> private void BindGiversGrid() { // Get all the selected criteria values var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( drpSlidingDateRange.DelimitedValues ); var start = dateRange.Start; var end = dateRange.End; var minAmount = nreAmount.LowerValue; var maxAmount = nreAmount.UpperValue; var currencyTypeIds = new List<int>(); cblCurrencyTypes.SelectedValues.ForEach( i => currencyTypeIds.Add( i.AsInteger() ) ); var sourceIds = new List<int>(); cblTransactionSource.SelectedValues.ForEach( i => sourceIds.Add( i.AsInteger() ) ); var accountIds = new List<int>(); foreach ( var cblAccounts in phAccounts.Controls.OfType<RockCheckBoxList>() ) { accountIds.AddRange( cblAccounts.SelectedValuesAsInt ); } var groupBy = hfGroupBy.Value.ConvertToEnumOrNull<ChartGroupBy>() ?? ChartGroupBy.Week; var graphBy = hfGraphBy.Value.ConvertToEnumOrNull<TransactionGraphBy>() ?? TransactionGraphBy.Total; GiversViewBy viewBy = GiversViewBy.Giver; if ( !HideViewByOption ) { viewBy = hfViewBy.Value.ConvertToEnumOrNull<GiversViewBy>() ?? GiversViewBy.Giver; } // Collection of async queries to run before assembling data var qryTasks = new List<Task>(); // Get all person summary data var personInfoList = new List<PersonInfo>(); qryTasks.Add( Task.Run( () => { var dt = FinancialTransactionDetailService.GetGivingAnalyticsPersonSummary( start, end, minAmount, maxAmount, accountIds, currencyTypeIds, sourceIds ) .Tables[0]; foreach ( DataRow row in dt.Rows ) { var personInfo = new PersonInfo(); if ( !DBNull.Value.Equals( row["Id"] ) ) { personInfo.Id = (int)row["Id"]; } if ( !DBNull.Value.Equals( row["Guid"] ) ) { personInfo.Guid = row["Guid"].ToString().AsGuid(); } if ( !DBNull.Value.Equals( row["NickName"] ) ) { personInfo.NickName = row["NickName"].ToString(); } if ( !DBNull.Value.Equals( row["LastName"] ) ) { personInfo.LastName = row["LastName"].ToString(); } if ( !DBNull.Value.Equals( row["Email"] ) ) { personInfo.Email = row["Email"].ToString(); } if ( !DBNull.Value.Equals( row["GivingId"] ) ) { personInfo.GivingId = row["GivingId"].ToString(); } if ( !DBNull.Value.Equals( row["FirstGift"] ) ) { personInfo.FirstGift = row["FirstGift"].ToString().AsDateTime(); } if ( !DBNull.Value.Equals( row["LastGift"] ) ) { personInfo.LastGift = row["LastGift"].ToString().AsDateTime(); } if ( !DBNull.Value.Equals( row["NumberGifts"] ) ) { personInfo.NumberGifts = (int)row["NumberGifts"]; } if ( !DBNull.Value.Equals( row["TotalAmount"] ) ) { personInfo.TotalAmount = (decimal)row["TotalAmount"]; } if ( !DBNull.Value.Equals( row["IsGivingLeader"] ) ) { personInfo.IsGivingLeader = (bool)row["IsGivingLeader"]; } if ( !DBNull.Value.Equals( row["IsAdult"] ) ) { personInfo.IsAdult = (bool)row["IsAdult"]; } if ( !DBNull.Value.Equals( row["IsChild"] ) ) { personInfo.IsChild = (bool)row["IsChild"]; } personInfo.AccountAmounts = new Dictionary<int, decimal>(); personInfoList.Add( personInfo ); } } ) ); // Get the account summary values DataTable dtAccountSummary = null; qryTasks.Add( Task.Run( () => { dtAccountSummary = FinancialTransactionDetailService.GetGivingAnalyticsAccountTotals( start, end, accountIds, currencyTypeIds, sourceIds ) .Tables[0]; } ) ); // Get the first/last ever dates var firstEverVals = new Dictionary<string, DateTime>(); var lastEverVals = new Dictionary<string, DateTime>(); qryTasks.Add( Task.Run( () => { var dt = FinancialTransactionDetailService.GetGivingAnalyticsFirstLastEverDates() .Tables[0]; foreach ( DataRow row in dt.Rows ) { if ( !DBNull.Value.Equals( row["GivingId"] ) ) { if ( !DBNull.Value.Equals( row["FirstEverGift"] ) ) { firstEverVals.Add( row["GivingId"].ToString(), row["FirstEverGift"].ToString().AsDateTime().Value ); } if ( !DBNull.Value.Equals( row["LastEverGift"] ) ) { lastEverVals.Add( row["GivingId"].ToString(), row["LastEverGift"].ToString().AsDateTime().Value ); } } } } ) ); // If a dataview filter was included, find the people who match that criteria List<int> dataViewPersonIds = null; var dataViewId = dvpDataView.SelectedValueAsInt(); if ( dataViewId.HasValue ) { qryTasks.Add( Task.Run( () => { dataViewPersonIds = new List<int>(); var dataView = new DataViewService( _rockContext ).Get( dataViewId.Value ); if ( dataView != null ) { var errorMessages = new List<string>(); var dvPersonService = new PersonService( _rockContext ); ParameterExpression paramExpression = dvPersonService.ParameterExpression; Expression whereExpression = dataView.GetExpression( dvPersonService, paramExpression, out errorMessages ); SortProperty sort = null; var dataViewPersonIdQry = dvPersonService .Queryable().AsNoTracking() .Where( paramExpression, whereExpression, sort ) .Select( p => p.Id ); dataViewPersonIds = dataViewPersonIdQry.ToList(); } } ) ); } qryTasks.Add( Task.Run( () => { // Clear all the existing grid columns var selectField = new SelectField(); var oldSelectField = gGiversGifts.ColumnsOfType<SelectField>().FirstOrDefault(); if ( oldSelectField != null ) { selectField.SelectedKeys.AddRange( oldSelectField.SelectedKeys ); } gGiversGifts.Columns.Clear(); // Add a column for selecting rows gGiversGifts.Columns.Add( selectField ); // Add a hidden column for person id gGiversGifts.Columns.Add( new RockBoundField { DataField = "Id", HeaderText = "Person Id", SortExpression = "Id", Visible = false, ExcelExportBehavior = ExcelExportBehavior.AlwaysInclude } ); // Add a column for the person's name gGiversGifts.Columns.Add( new RockBoundField { DataField = "PersonName", HeaderText = "Person", SortExpression = "LastName,NickName" } ); // add a column for email (but is only included on excel export) gGiversGifts.Columns.Add( new RockBoundField { DataField = "Email", HeaderText = "Email", SortExpression = "Email", Visible = false, ExcelExportBehavior = ExcelExportBehavior.AlwaysInclude } ); // Add a column for total amount gGiversGifts.Columns.Add( new CurrencyField { DataField = "TotalAmount", HeaderText = "Total", SortExpression = "TotalAmount" } ); // Add columns for the selected account totals if ( accountIds.Any() ) { var accounts = new FinancialAccountService( _rockContext ) .Queryable().AsNoTracking() .Where( a => accountIds.Contains( a.Id ) ) .ToList(); foreach ( int accountId in accountIds ) { var account = accounts.FirstOrDefault( a => a.Id == accountId ); if ( account != null ) { gGiversGifts.Columns.Add( new GivingAnalyticsAccountField { DataField = string.Format( "Account_{0}", account.Id ), HeaderText = account.Name, SortExpression = string.Format( "Account:{0}", account.Id ), } ); } } } // Add a column for the number of gifts var numberGiftsField = new RockBoundField { DataField = "NumberGifts", HeaderText = "Number of Gifts", SortExpression = "NumberGifts", DataFormatString = "{0:N0}", }; numberGiftsField.ItemStyle.HorizontalAlign = HorizontalAlign.Right; gGiversGifts.Columns.Add( numberGiftsField ); if ( !radFirstTime.Checked ) { // Add a column to indicate if this is a first time giver gGiversGifts.Columns.Add( new BoolField { DataField = "IsFirstEverGift", HeaderText = "Is First Gift", SortExpression = "IsFirstEverGift" } ); // Add a column for the first gift date ( that matches criteria ) gGiversGifts.Columns.Add( new DateField { DataField = "FirstGift", HeaderText = "First Gift in Period", SortExpression = "FirstGift" } ); } // Add a column for the first-ever gift date ( to any tax-deductible account ) gGiversGifts.Columns.Add( new DateField { DataField = "FirstEverGift", HeaderText = "First Gift Ever", SortExpression = "FirstEverGift" } ); // Add a column for the first gift date ( that matches criteria ) gGiversGifts.Columns.Add( new DateField { DataField = "LastGift", HeaderText = "Last Gift in Period", SortExpression = "LastGift" } ); // Add a column for the last-ever gift date ( to any tax-deductible account ) gGiversGifts.Columns.Add( new DateField { DataField = "LastEverGift", HeaderText = "Last Gift Ever", SortExpression = "LastEverGift" } ); } ) ); // Wait for all the queries to finish Task.WaitAll( qryTasks.ToArray() ); // If dataview was selected and it's being used to filter results people, not in dataview if ( dataViewId.HasValue && rblDataViewAction.SelectedValue != "All" && dataViewPersonIds.Any() ) { personInfoList = personInfoList.Where( c => dataViewPersonIds.Contains( c.Id ) ).ToList(); } // if dataview was selected and it includes people not in the result set, if ( dataViewId.HasValue && rblDataViewAction.SelectedValue == "All" && dataViewPersonIds.Any() ) { // Query for the names of each of these people foreach ( var person in new PersonService( _rockContext ) .Queryable().AsNoTracking() .Where( p => dataViewPersonIds.Contains( p.Id ) ) .Select( p => new { p.Id, p.GivingId, p.GivingLeaderId, p.Guid, p.NickName, p.LastName, p.Email } ) ) { // Check for a first ever gift date var firstEverGiftDate = firstEverVals .Where( f => f.Key == person.GivingId ) .Select( f => f.Value ) .FirstOrDefault(); // Check for a last ever gift date var lastEverGiftDate = lastEverVals .Where( f => f.Key == person.GivingId ) .Select( f => f.Value ) .FirstOrDefault(); var personInfo = new PersonInfo(); personInfo.Id = person.Id; personInfo.Guid = person.Guid; personInfo.NickName = person.NickName; personInfo.LastName = person.LastName; personInfo.Email = person.Email; personInfo.GivingId = person.GivingId; personInfo.IsGivingLeader = person.Id == person.GivingLeaderId; personInfo.FirstEverGift = firstEverGiftDate; personInfo.LastEverGift = lastEverGiftDate; personInfoList.Add( personInfo ); } } // Filter out recs that don't match the view by switch ( viewBy ) { case GiversViewBy.Giver: { personInfoList = personInfoList.Where( p => p.IsGivingLeader ).ToList(); break; } case GiversViewBy.Adults: { personInfoList = personInfoList.Where( p => p.IsAdult ).ToList(); break; } case GiversViewBy.Children: { personInfoList = personInfoList.Where( p => p.IsChild ).ToList(); break; } } // Add the first/last gift dates foreach ( var personInfo in personInfoList ) { if ( firstEverVals.ContainsKey( personInfo.GivingId ) ) { personInfo.FirstEverGift = firstEverVals[personInfo.GivingId]; } if ( lastEverVals.ContainsKey( personInfo.GivingId ) ) { personInfo.LastEverGift = lastEverVals[personInfo.GivingId]; } } // Check to see if we're only showing first time givers if ( radFirstTime.Checked ) { personInfoList = personInfoList .Where( p => p.IsFirstEverGift ) .ToList(); } // Check to see if grid should display only people who gave a certain number of times and if so // set the min value if ( radByPattern.Checked ) { int minCount = tbPatternXTimes.Text.AsInteger(); var previousGivingIds = new List<string>(); if ( cbPatternAndMissed.Checked ) { var missedStart = drpPatternDateRange.LowerValue; var missedEnd = drpPatternDateRange.UpperValue; if ( missedStart.HasValue && missedEnd.HasValue ) { // Get the givingleaderids that gave any amount during the pattern's date range. These // are needed so that we know who to exclude from the result set previousGivingIds = new FinancialTransactionDetailService( _rockContext ) .Queryable().AsNoTracking() .Where( d => d.Transaction.TransactionDateTime.HasValue && d.Transaction.TransactionDateTime.Value >= missedStart.Value && d.Transaction.TransactionDateTime.Value < missedEnd.Value && ( accountIds.Any() && accountIds.Contains( d.AccountId ) || d.Account.IsTaxDeductible ) && d.Amount != 0.0M ) .Select( d => d.Transaction.AuthorizedPersonAlias.Person.GivingId ) .ToList(); } } personInfoList = personInfoList .Where( p => !previousGivingIds.Contains( p.GivingId ) && p.NumberGifts >= minCount ) .ToList(); } // Add account summary info foreach ( DataRow row in dtAccountSummary.Rows ) { if ( !DBNull.Value.Equals( row["GivingId"] ) && !DBNull.Value.Equals( row["AccountId"] ) && !DBNull.Value.Equals( row["Amount"] ) ) { string givingId = row["GivingId"].ToString(); int accountId = (int)row["AccountId"]; decimal amount = (decimal)row["Amount"]; foreach ( var personInfo in personInfoList.Where( p => p.GivingId == givingId ) ) { personInfo.AccountAmounts.AddOrIgnore( accountId, amount ); } } } // Calculate Total if ( viewBy == GiversViewBy.Giver ) { pnlTotal.Visible = true; decimal amountTotal = personInfoList.Sum( p => p.TotalAmount ); lTotal.Text = amountTotal.FormatAsCurrency(); } else { pnlTotal.Visible = false; } var qry = personInfoList.AsQueryable(); if ( gGiversGifts.SortProperty != null ) { if ( gGiversGifts.SortProperty.Property.StartsWith( "Account" ) ) { int? accountId = gGiversGifts.SortProperty.Property.Substring( 8 ).AsIntegerOrNull(); if ( accountId.HasValue ) { foreach ( var personInfo in personInfoList ) { personInfo.SortAmount = personInfo.AccountAmounts.ContainsKey( accountId.Value ) ? personInfo.AccountAmounts[accountId.Value] : 0.0M; if ( gGiversGifts.SortProperty.Direction == SortDirection.Ascending ) { gGiversGifts.DataSource = personInfoList.OrderBy( p => p.SortAmount ).ToList(); } else { gGiversGifts.DataSource = personInfoList.OrderByDescending( p => p.SortAmount ).ToList(); } } } else { gGiversGifts.DataSource = qry.OrderBy( p => p.LastName ).ThenBy( p => p.NickName ).ToList(); } } else { gGiversGifts.DataSource = qry.Sort( gGiversGifts.SortProperty ).ToList(); } } else { gGiversGifts.DataSource = qry.OrderBy( p => p.LastName ).ThenBy( p => p.NickName ).ToList(); } gGiversGifts.DataBind(); }