Cannot access a disposed object

2019-08-27 16:03发布

问题:

i'm facing a issue while testing the DAL Library which uses LINQ to SQL

Method that is being Tested as below (a simple one):

public List<tblAccount> GetAccountsByCustomer(tblCustomer customer)
{
    using (OnlineBankingDataClassesDataContext dbcntx = new OnlineBankingDataClassesDataContext())
    {
        var accounts = dbcntx.tblAccounts.Where(p => p.tblCustomer.ID.CompareTo(customer.ID)==0);
        return accounts.ToList<tblAccount>();
    }
}

Test code is as below:

static tblCustomer GetTopOneCustomer()
{
    OnlineBankingDataClassesDataContext dbcntx = new OnlineBankingDataClassesDataContext();
    var customers = dbcntx.tblCustomers.Take(1);
    return customers.Single<tblCustomer>();
}

public static void Should_List_All_Account_By_Customer()
{

    tblCustomer customer = GetTopOneCustomer();

    DataController dc = new DataController();
    List<tblAccount> accounts=dc.GetAccountsByCustomer(customer);
    foreach (tblAccount account in accounts)
    {
        string accountdetails=string.Format("Account ID:{0} \n Account Type:{1} \n Balance:{2} \n BranchName:{3} \n AccountNumber:{4}",
                        account.ID.ToString(), account.tblAccountType.Name, 
                        account.Balance.ToString(),
                        account.tblBranch.Name, account.Number);

        Console.WriteLine(accountdetails);

    }
}

I'm getting an error "Cannot access a disposed object." when accessing associated object like in this case, I'm using account.tblAccountType.Name. I know it has something to do with DataContext. How shall I get this code working.

回答1:

dbcntx is a disposable object. The Garbage Collector can come along at any time after GetTopOneCustomer() has been called and dispose of it. Which is what looks like is happening.

Try changing GetTopOneCustomer() to:

static tblCustomer GetTopOneCustomer(OnlineBankingDataClassesDataContext dataContext) 
{
    //Stuff
}

Then inside Should_List_All_Account_By_Customer() change it like so:

using (OnlineBankingDataClassesDataContext dataContext = new OnlineBankingDataClassesDataContext())
{
    tblCustomer customer = GetTopOneCustomer(dataContext); 
    //More Stuff
}

This way you control the lifetime of the dataContext.



回答2:

Since the the DataContext is in a using statement, using (OnlineBankingDataClassesDataContext dbcntx = new OnlineBankingDataClassesDataContext()) Disposed will be called on it as soon as the context goes out of scope. This results in all entities beeing detached and all actions on the entity that requires a DataContext will fail. This is what happens when account.Balance.ToString() is called.

One way to solve this is by creating a new context and use context.Attach(entity).