I'm having one issue with LINQ to SQL for Windows Phone (SQL Server CE).
I'm developing an personal finance app, and then I have the Account class and the Transaction class. Each Transaction class have a reference to the account it belongs to, so the Account class have a collection of transactions, in a one-to-many relationship. Then I have the repositories (AccountRepository and TransactionRepository) that expose methods to insert, delete, findbykey, and return all instances of each of this classes. The ViewModel have references to its repositories. OK, everything works just well, but, when I create a transaction, it doesn't appear in the Account.Transactions collection untill I stop the software and run it again.
Here's some pieces of the code, first, the model classes:
[Table]
public class Transaction : INotifyPropertyChanged, INotifyPropertyChanging
{
// {...}
[Column]
internal int _accountID;
private EntityRef<Account> _account;
[Association(Storage = "_account", ThisKey = "_accountID")]
public Account Account
{
get {return _account.Entity;}
set
{
NotifyPropertyChanging("Account");
_account.Entity = value;
if (value != null)
{
_accountID = value.AccountID;
}
NotifyPropertyChanged("Account");
}
}
// {...}
}
[Table]
public class Account : INotifyPropertyChanged, INotifyPropertyChanging
{
// {...}
private EntitySet<Transaction> _transactions;
[Association(Storage = "_transactions", OtherKey = "_accountID")]
public EntitySet<Transaction> Transactions
{
get { return this._transactions; }
set { this._transactions.Assign(value); }
}
public Account()
{
_transaction = new EntitySet<Transaction>(
new Action<Transaction>(this.attach_transaction),
new Action<Transaction>(this.detach_transaction)
);
}
private void attach_transaction(Transaction transaction)
{
NotifyPropertyChanging("Transactions");
transaction.Account = this;
}
private void detach_transaction(Transaction transaction)
{
NotifyPropertyChanging("Transactions");
transaction.Account = null;
}
// {...}
}
Then I have some repositories that implement a GetAll() method that returns an ObservableCollection. The repositories have a reference to the Context class that is created inside the ViewModel class and, like this:
public class AccountRepository
{
private MyContext _context;
public AccountRepository(ref MyContext context)
{
_context = context;
}
// {...}
public ObservableCollection<Account> GetAll()
{
return new ObservableCollection(_context.Accounts.Where([some paramethers]).AsEnumerable());
}
// {...}
}
My ViewModel initialize the repositories in the constructor and then expose methods with some few logic code to insert, delete, etc., each of this types.
public class MyViewModel : INotifyPropertyChanged, INotifyPropertyChanging
{
private MyContext _context;
private AccountRepository accountRepository;
private TransactionRepository transactionRepository;
public ObservableCollection<Account> AllAccounts;
public ObservableCollection<Transaction> AllTransactions;
public MyViewModel(string connectionString)
{
_context = new MyContext("Data Source=’isostore:/mydatabase.sdf’"); if (!db.DatabaseExists()) db.CreateDatabase();
accountRepository = new AccountRepository(ref _context);
transactionRepository = new TransactionRepository(ref _context);
// [Some other code]
LoadCollections();
}
// {...}
public void LoadCollections()
{
AllAccounts = accountRepository.GetAll();
NotifyPropertyChanged("AllAccounts");
AllTransactions = transactionRepository.GetAll();
NotifyPropertyChanged("AllTransactions");
}
public void InsertTransaction(Transaction transaction)
{
AllTransactions.Add(transaction);
transactionRepository.Add(transaction);
LoadCollections(); // Tried this to update the Accounts with newer values, but don't work...
}
// {...}
}
When the user create a Transaction, the page calls the InsertTransaction (Transaction transaction) method in the view model, that pass the transaction object to the repository. But the Transactions collection in the Account object doesn't get updated. Then I tried to call the LoadCollections() method to force a new query in the context, and try to somehow get a fresh account object, but it still without the recently created transaction. If I stop my app and start it again, the Accounts are up to date and have all transactions I've created in the last run within its transactions collection.
How can I update this Transactions collection at runtime?
Updating the question:
I had some feedback regarding to notifying the UI that the collection was changed.
I think it's a problem with the association between transactions and account. Once I create a transaction, it won't appear in it's account.Transactions collection until I dispose my context and create it again.
It may be some notify fault, but I DON'T think it is and I did some code to try to prove it, I'm not in my PC right now but I'll try to explain my test.
The code I did to prove it was something like this:
Account c1 = context.Accounts.Where(c => c.AccountID == 1).SingleOrDefault();
Transaction t1 = new Transaction() { Account = c1, {...} };
context.Transactions.InsertOnSubmit(t1);
context.SaveChanges();
c1 = context.Accounts.Where(c => c.AccountID == 1).SingleOrDefault();
// The transaction IS NOT in the c1.Transactions collection right NOW.
context.Dispose();
context = new MyContext({...});
c1 = context.Accounts.Where(c => c.AccountID == 1).SingleOrDefault();
// The transaction IS in the c1.Transactions after the dispose!
Account c2 = context.Where(c => c.AccountID == 2).SingleOrDefault();
t1 = context.Transactions.Where(t => t.TransactionID == x).SingleOrDefault();
t1.Account = c2;
context.SubmitChanges();
c1 = context.Accounts.Where(c => c.AccountID == 1).SingleOrDefault();
// The transaction still in the c1 collection!!!
c2 = context.Accounts.Where(c => c.AccountID == 2).SingleOrDefault();
// It should be in the c2 collection, but isn't yet...
context.Dispose();
context = new MyContext({...});
c1 = context.Accounts.Where(c => c.AccountID == 1).SingleOrDefault();
// The transaction is not in the c1.Transaction anymore!
c2 = context.Accounts.Where(c => c.AccountID == 2).SingleOrDefault();
// The transaction IS in the c2.Transactions now!