So. This may be a stupid question, but...
I'm limited to using a database that doesn't support EntityFramework but I'd still like to separate out my data layer into a separate assembly. That means I'd need to share domain object values yet avoid a circular reference between my business and data layers. I therefore wondered whether it would be acceptable to construct a repository of persistence interfaces that could be implemented by the business layer and passed to the data layer independently of each other.
Example as follows:
// Business Layer
public class Customer: IPersistableCustomer
{
private string name;
public string Name{ get { return this.name; } }
public void persist()
{
dataLayer.StoreCustomerInstance(this);
}
}
// DataLayer
public StoreCustomerInstance(IPersistableCustomer persistableCustomer)
{
// Do storage stuff
}
// Interface repository
public interface IPersistableCustomer
{
string Name { get; }
}
I'm almost certain this is a terrible idea but I'm not sure why. I'd be interested to know people's thoughts to see where any potential pitfalls might be.
What you're doing in your example is hide your domain objects behind an interface. What you should do is hide your data layer behind interfaces. This abstraction of the data layer is commonly known as the repository pattern.
In the business layer you define the domain classes and repository interfaces:
public class Customer
{
public Customer(string name)
{
this.Name = name;
}
public string Name { get; private set; }
}
public interface ICustomerRepository
{
void Save(Customer customer);
}
Note that the Customer class doesn't have any persistence logic. Neither does the repository interface; it only defines the contract of the data layer.
The implementation of the contract goes in the data layer:
public class SqlCustomerRepository : ICustomerRepository
{
public void Save(Customer customer)
{
// Persistence logic
}
}
At this point the data layer needs a reference to the business layer, but not the other way around.
You tie these two layers together in the application layer:
class CustomerForm
{
private readonly ICustomerRepository customerRepository;
// This class declares a dependency on any ICustomerRepository
public CustomerForm(ICustomerRepository customerRepository)
{
this.customerRepository = customerRepository;
}
public void PersistCustomer()
{
Customer customer = CreateCustomerFromUserInput();
this.customerRepository.Save(customer);
}
}
class Program
{
static void Main(string[] args)
{
// Dependency injection, usually done via a DI container
var customerRepository = new SqlCustomerRepository();
var form = new CustomerForm(customerRepository);
form.PersistCustomer();
}
}
I found the articles on the Onion Architecture very valuable when faced with the same question as you. It explains how to set up your application's architecture in a way that prevents tight coupling to the data layer.
Another advantage of using interfaces for the data layer is that it allows you to unit tests most of your code without having to have an actual database running. You can simply mock the repository interfaces.
I once used interfaces for my domain objects a few years ago. I don't regret it, because it taught me how not to do it. But that's the only good thing; it was a lot of extra work and maintenance without any real benefits :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With