How to persist a property of type an interface in Entity Framework Core?

Viewed 423

In my application, expenses could have many resources like Bank account or cash money in your safe or a family member likes to give you money to buy whatever you want...

So I have a Bank class which it has multiple accounts and a safe class. Account and safe are marked with IFinancialResource.

public interface IFinancialResource
{
    public decimal Balance { get; }
    public void SetBalance(decimal amount);
    public void Deposite(decimal amount);
    public void Withdraw(decimal amount);
}

public class Bank : BaseEntity, IAggregateRoot
{
    public string Name { get; private set; }
    public string WebSite{ get; private set; }
    public Address Address { get; private set; }

    private readonly List<Account> _accounts = new List<Account>();
    public IReadOnlyCollection<Account> Accounts => _accounts.AsReadOnly();
}

public class Account :  BaseEntity, IFinancialResource
{
    public string AccountNumber { get; private set; }
    public decimal Balance { get; private set; }
    public AccountType AccountType { get; private set; }
    public int AccountTypeId { get; private set; }

    //to make a not null foreign key
    public int BankId { get; private set; }

    public Account(int accountTypeId, string accountNumber, decimal balance)
    {
        AccountNumber = accountNumber;
        SetBalance(balance);
        AccountTypeId = accountTypeId;
    }

    public void SetBalance(decimal amount)
    {
        Balance = amount;
    }

    public void Deposit(decimal amount)
    {
        Balance += amount;
    }

    public void Withdraw(decimal amount)
    {
        if ((Balance - amount) < 0) 
             return;
        Balance -= amount;
    }
}

public class Safe : BaseEntity, IFinancialResource, IAggregateRoot
{
    public string Name { get; private set; }
    public decimal Balance { get; private set; }

    public Safe(string name, decimal balance)
    {
        Validate.NullOrEmpty(name, nameof(name));

        Name = name;
        SetBalance(balance);
    }

    public void SetBalance(decimal amount)
    {
        Validate.OutOfRange(amount, nameof(amount), 0, decimal.MaxValue);
        Balance = amount;
    }

    public void Deposit(decimal amount)
    {
        Validate.OutOfRange(amount, nameof(amount), 0, decimal.MaxValue);
        Balance += amount;
    }

    public void Withdraw(decimal amount)
    {
        Validate.OutOfRange(amount, nameof(amount), 0, decimal.MaxValue);

        if ((Balance - amount) < 0) 
            return;

        Balance -= amount;
    }
}

Now I want to define a class named FinancialActivity which has a property of type IFinancialResource interface as the source of each expense.

The problem is Entity Framework Core doesn't persist interface properties. How should I persist each expense's resource in the FinancialActivity class?

public class FinancialActivity : BaseEntity, IAggregateRoot
{
    public string ActivityDate { get; private set; }
    public string Subject { get; private set; }
    public double Latitude { get; private set; }
    public double Longitude { get; private set; }
    public Address Address { get; private set; }
    public IFinancialResource FinancialResource { get; private set; }
}
1 Answers

This isn't an EF Core question so much as a database persistence question. Navigation properties represent foreign keys, so how would you model this in SQL Server (for example)? If you can model it in SQL Server, you can almost always represent it in EF Core. If there isn't a concrete representation to model in the database, how would the foreign keys be set up?

There are quite a bit of missing classes in your example, so I couldn't recreate it, but the basic answer is that you have to be able to map your models to persistent types, so you will want to map to the base class and use derived classes for your unique types. I also noticed you are mixing business logic with your persistence entities, which is usually not a good idea. (Note: I say usually because there aren't any absolutes in development). Might want to look at the decorator pattern to accomplish the different methods that you are implementing in your different types.

Related