I am using .NET Core with Entity Framework Core to build a finance app and I want to know how to make my design better.
I have a 1 to Many relationship between two entities, BankAccount
and Transaction
. In a way that:
- 1 Account can have many Transactions
- 1 Transaction Belongs to 1 Account
However, I want to include bank accounts and transactions coming from different 3P sources. And while this relationship and the main fields are common across different sources, each source has a unique set of properties I want to keep.
To achieve this I decided to define these entities as abstract classes. This way, you can only instantiate concrete versions of these entities, each coming from a particular data source.
public abstract class Transaction : BaseEntity
{
public DataSource Source { get; private set; }
public decimal Amount { get; private set; }
public DateTime Date { get; private set; }
public string Name { get; private set; }
public BankAccount BankAccount { get; private set; }
public Guid BankAccountId { get; private set; }
...
}
public abstract class BankAccount : BaseEntity
{
public DataSource Source { get; private set; }
public string Name { get; private set; }
public Balance Balance { get; private set; }
public IEnumerable<Transaction> Transactions {get; private set;}
...
}
Here is a trimmed down example of the concrete implementations:
public class PlaidTransaction : Transaction
{
public string PlaidId { get; private set; }
private PlaidTransaction() : base() { }
public PlaidTransaction(decimal amount, DateTime date, string name, Guid bankAccountId, string plaidId) : base( amount, date, name, bankAccountId)
{
PlaidId = plaidId;
}
}
public class PlaidBankAccount : BankAccount
{
public string PlaidId { get; private set; }
...
}
I am using .Net Core with Entity Framework Core to persist my data and I managed to store my concrete classes all in the same table (TPH approach)
This works great and now all my entities live under the same table. So I can either query all Transactions or those of a certain type using LINQ's OfType<T>
extension.
DbSet<Transaction> entities = _context.Set<Transaction>();
IEnumerable<PlaidTransaction> plaidTransactions = entities.OfType<PlaidTransaction>();
However, when I access my BankAccount field from my concrete Transaction I don't get the concrete instance. So something like this doesn't work.
plaidTransactions.Where((t) => t.BankAccount.PlaidId)
Instead I have to cast it:
plaidTransactions.Where((t) => (t.BankAccount as PlaidBankAccount).PlaidId)
What can I do to avoid casting everywhere? I feel there's a missing piece in my design that would make all my code easier. I was thinking of overriding the getters on my concrete classes but I don't know if I can return a derived class to a base class method. Maybe I should move to generics but 1) I still want to keep the fixed relationship between these entities and 2) how would EF Core handle this?
Aucun commentaire:
Enregistrer un commentaire