سؤال

I'm having an issue with the following code.

public IEnumerable<BillingConfiguration> GetBillingConfigurationsForAccount(int accountId, DateTime? effectiveDate)
    {
        var result = new List<BillingConfiguration>();
        var accountIds = new List<int>();
        var billingGroupIds = new List<int>();

        using (var context = new GbContext())
        {
            var account = context.Accounts.Where(a => a.AccountId == accountId).SingleOrDefault();
            if (account.ParentAccountId == null) // This is a parent account
            {
                // Get list of sub account ids
                accountIds = context.Accounts.Where(a => a.ParentAccountId == accountId).Select(x => x.AccountId).ToList();
                accountIds.Add(accountId);
            }
            else // This is a sub account
            {
                accountIds.Add(accountId);
            }

            // Get list of Billing Configurations for all accountIds
            IQueryable<BillingConfigurationAccount> accountQuery = context.BillingConfigurationAccounts
                .Where(a => accountIds.Contains(a.AccountId)).AsQueryable();
            AddBillingConfigurationAccountIncludes(accountQuery);
            var accountBillingConfigurations = accountQuery.ToList();

            //IQueryable<BillingConfigurationAccount> accountQuery = context.BillingConfigurationAccounts;
            //AddBillingConfigurationAccountIncludes(accountQuery);
            //accountQuery = accountQuery.Where(a => accountIds.Contains(a.AccountId));
            //var accountBillingConfigurations = accountQuery.ToList();   

            if (accountBillingConfigurations.HasValues())
            {
                accountBillingConfigurations.ForEach(x => result.Add(x.BillingConfiguration));
            }

            return result;
        }
    }
private void AddBillingConfigurationAccountIncludes(IQueryable<BillingConfigurationAccount> query)
    {
        query = query
            .Include(p => p.BillingConfiguration)
            .Include(p => p.BillingConfiguration.BillingConfigurationLevel)
            .Include(p => p.BillingConfiguration.BillType)
            .Include(p => p.BillingConfiguration.PayerOptionType)
            .Include(p => p.BillingConfiguration.BillModeOptions)
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.BillMode))
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.FirstPastDueDateOptionsType))
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.LapseNoticeOptionsType))
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.PaymentDueDateOptionsType))
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.PaymentGracePeriodType))
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.SecondPastDueDateOptionsType))
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.BillModeOptionPaymentMethods))
            .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.BillModeOptionPaymentMethods.Select(n => n.PaymentMethodType)));
    }

When I look at the accountBillingConfigurations it has 2 items in the list, however the BillingConfiguration entity is null, the BillingConfigurationId is there and correct, but its not bringing back the BillingConfiguration entity.

Now if I do everything inline like this it works as expected. The where clause and the includes are identical.

public IEnumerable<BillingConfiguration> GetBillingConfigurationsForAccount(int accountId, DateTime? effectiveDate)
    {
        var result = new List<BillingConfiguration>();
        var accountIds = new List<int>();
        var billingGroupIds = new List<int>();

        using (var context = new GbContext())
        {
            var account = context.Accounts.Where(a => a.AccountId == accountId).SingleOrDefault();
            if (account.ParentAccountId == null) // This is a parent account
            {
                // Get list of sub account ids
                accountIds = context.Accounts.Where(a => a.ParentAccountId == accountId).Select(x => x.AccountId).ToList();
                accountIds.Add(accountId);
            }
            else // This is a sub account
            {
                accountIds.Add(accountId);
            }

            // Get list of Billing Configurations for all accountIds
            var accountBillingConfigurations = context.BillingConfigurationAccounts
                .Include(p => p.BillingConfiguration)
                .Include(p => p.BillingConfiguration.BillingConfigurationLevel)
                .Include(p => p.BillingConfiguration.BillType)
                .Include(p => p.BillingConfiguration.PayerOptionType)
                .Include(p => p.BillingConfiguration.BillModeOptions)
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.BillMode))
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.FirstPastDueDateOptionsType))
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.LapseNoticeOptionsType))
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.PaymentDueDateOptionsType))
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.PaymentGracePeriodType))
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.SecondPastDueDateOptionsType))
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.BillModeOptionPaymentMethods))
                .Include(p => p.BillingConfiguration.BillModeOptions.Select(m => m.BillModeOptionPaymentMethods.Select(n => n.PaymentMethodType)))
                .Where(a => accountIds.Contains(a.AccountId));

            if (accountBillingConfigurations.HasValues())
            {
                accountBillingConfigurations.ForEach(x => result.Add(x.BillingConfiguration));
            }

            return result;
        }
    }

That code actually fills out the BillingConfiguration entity and all its sub entities. Is what I'm trying to do possible? and if, so what am I doing wrong?

Thanks

هل كانت مفيدة؟

المحلول

This is a subtle one.

You correctly assume that a method like

void SomeMethod(IQueryable<T> query)

can modify the reference object it receives and that these modifications will be visible outside the scope of the method.

However... the method doesn't modify the object, it replaces it. The assignment = assigns the return value of the Include method to the query variable. Now inside the method, the previous query variable is out of scope, because the reference is overwritten by a reference to the new object. But outside the method this new reference will never be known. There the old reference still applies.

The remedy is simple: return the new reference:

IQueryable<T> SomeMethod(IQueryable<T> query)

In you case this would become:

accountQuery = AddBillingConfigurationAccountIncludes(accountQuery);

If you don't believe me, try this little program in Linqpad :)

void Main()
{
    var ints = Enumerable.Range(1,10).ToArray();
    AddInt(ints, 11);
    ints.Dump();
}

void AddInt(IEnumerable<int> list, int i)
{
    list = list.Concat(new[] {i});
    list.Dump();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top