Sono in fase di refactoring del codice legacy. Sfortunatamente si tratta di un'applicazione WebForms con un codice molto stretto e maleodorante. Attualmente l'accesso al database è all'interno di modelli che assomigliano a questo:
var fooModel = new FooModel();
fooModel.Select(sqlConnection); // Accesses db and populates model's data.
Vorrei spostare questa logica in Data Access Layer e nel processo renderlo facile da testare, quindi in futuro potrò migrare a MVC senza troppi problemi. Attualmente il codice non usa alcun ORM, quindi devo attenermi a SqlConnection
.
Ho trovato un modo per astrarre l'accesso al database, ma non so come renderlo facile da testare. Ho deciso di creare questa gerarchia:
Controller(currently codebehind) -> Services -> UnitOfWork -> Repositories -> SqlConnection to db
.
Fondamentalmente Controllers
può vedere solo Services
che utilizza UnitOfWork
per accedere a Repositories
per utilizzare le transazioni e recuperare i dati.
Ho creato un campione per mostrarti cosa intendo e qual è il problema attuale. Ho usato semplice List
invece di connettermi effettivamente al database, perché è solo un esempio per mostrare quello che sto cercando e sono aperto a cambiare e riscrivere completamente se qualcuno ha più conoscenza di questo tipo di problemi. / p>
Servizio di esempio:
public class CustomerService : ICustomerService
{
public int AddCustomer(Customer customer)
{
using (var uof = new UnitOfWork())
{
var customerId = uof.CustomerRepository.Add(customer);
var customerAddressId = uof.CustomerAddressRepository.Add(customer.Address);
var customerAddress = uof.CustomerAddressRepository.Get(customerAddressId);
customer.CustomerAddressId = customerAddressId;
customer.Address = customerAddress;
uof.CustomerRepository.Update(customer);
uof.Commit();
return customerId;
}
}
public void UpdateCustomer(Customer customer)
{
using (var uof = new UnitOfWork())
{
uof.CustomerRepository.Update(customer);
uof.Commit();
}
}
public Customer GetCustomerById(int customerId)
{
using (var uof = new UnitOfWork())
{
return uof.CustomerRepository.Get(customerId);
}
}
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork, IDisposable
{
public ICustomerRepository CustomerRepository { get; }
public ICustomerAddressRepository CustomerAddressRepository { get; }
private SqlConnection _sqlConnection;
private SqlTransaction _transaction;
public UnitOfWork()
{
_sqlConnection = new SqlConnection();
_transaction = _sqlConnection.BeginTransaction();
CustomerRepository = new CustomerRepository(_sqlConnection);
CustomerAddressRepository = new CustomerAddressRepository(_sqlConnection);
}
public void Commit()
{
_transaction.Commit();
}
public void Dispose()
{
_sqlConnection.Dispose();
}
}
Repository di esempio:
public class CustomerRepository : ICustomerRepository
{
private readonly SqlConnection _connection;
private readonly List<Customer> _customers;
public CustomerRepository(SqlConnection connection)
{
_connection = connection;
_customers = new List<Customer>();
}
public int Add(Customer customer)
{
var id = _customers.Count + 1;
customer.CustomerId = id;
_customers.Add(customer);
return id;
}
public void Update(Customer newCustomer)
{
var index = _customers.FindIndex(f => f.CustomerId == newCustomer.CustomerId);
_customers.RemoveAt(index);
_customers.Add(newCustomer);
}
public Customer Get(int id)
{
return _customers.FirstOrDefault(f => f.CustomerId == id);
}
}
Come i controllori (codebehind corrente) usano questo:
var customer = _customerService.GetCustomerById(1);
var specificCustomers = _customerService.GetCustomersByIds(new int[] {5, 63, 75});
Con l'approccio attuale non posso prendere in giro ICustomerRepository
nella mia classe UnitOfWork
. Anch'io ho una serie di schemi misti e ciò di cui ho bisogno insieme, quindi non sono sicuro se questo è il modo per andare qui. Cosa posso fare per creare repository in UnitOfWork
testabile?