Прежде всего, мне жаль, если это будет длинный пост, но я не знаю, как правильно объяснить проблему без необходимых деталей.Отвлечься от реализации DAL из Entity Framework
У меня возникли проблемы с поиском способа абстрагирования моего DAL из реализации Entity Framework. Проект, над которым я работаю, очень мал, но если в будущем я захочу переключиться на другой ORM, например, NHibernate или просто ADO.NET, я бы хотел написать код только для реализации, а не для всего DAL ,
Скажем, у меня есть эти сущности в моем MyWallet.DAL:
public interface IWallet {
long Id { get; set; }
float TotalAmountOfMoney { get; set; }
long CurrencyId { get; set; }
ICurrency Currency { get; set; }
DateTime RecordedOn { get; set; }
ICollection<IMoneyMovement> MoneyMovements { get; set; }
}
public interface ICurrency {
long Id { get; set; }
char Symbol { get; set; }
string Code { get; set; }
string Description { get; set; }
}
public interface IMoneyMovement {
long Id { get; set; }
float Amount { get; set; }
string Description { get; set; }
long WalletId { get; set; }
IWallet Wallet { get; set; }
DateTime RecordedOn { get; set; }
DateTime MovedOn { get; set; }
}
Как вы можете видеть эти простые интерфейсы, которые я планирую реализовать на другую библиотеку, которая будет содержать фактическую реализацию Entity Framework (скажем MyWallet. DAL.EntityFramework). Конечно, я собираюсь украсить реализацию сущностей специальными атрибутами Entity Framework как [Key] или [ForeignKey] и тому подобное.
Я также определил некоторый репозиторий в MyWallet.DAL, например IWalletRepository, IMoneyMovementRepository, ICurrencyRepository, чтобы получить доступ к объектам. На самом деле я не знаю, является ли это правильным способом создания доступа к объектам. Конечно, я также определил фабрики, чтобы получить конкретную реализацию сущностей.
В моей бизнес-уровне, я определил услуги для обработки запроса объекта, работы с DAL субъектами и вернуть бизнес-объект, например:
public class WalletService {
private readonly IWalletRepository _walletRepository;
private readonly IWalletFactory _walletFactory;
public WalletService(IWalletRepository walletRepository,
IWalletFactory walletFactory) {
_walletRepository = walletRepository;
_walletFactory = walletFactory;
}
public CreatedWallet CreateWallet(CreateWalletRequest request) {
var wallet = _walletFactory.Create();
wallet.CurrencyId = request.CurrencyId;
wallet.TotalAmountOfMoney = request.TotalAmountOfMoney;
wallet.RecordedOn = DateTime.Now;
_walletRepository.Create(wallet);
_walletRepository.SaveChanges();
return new CreatedWallet {
Id = wallet.Id
}
}
}
Я думал, что это будет работать без проблем, или в худшем случае - в ситуации, когда у меня есть несколько репозиториев, я мог бы поделиться DataContext, поэтому мне нужно запустить метод SaveChanges только один, чтобы отразить изменения в базе данных.
Проблема заключается в реализации хранилища, в этом случае я буду продолжать с Entity Framework:
public class EFDataContext : DbContext {
public EFDataContext() : base ("name=MyConnectionString") {
}
public virtual DbSet<EFWallet> Wallets { get; set; }
public virtual DbSet<EFMoneyMovement> MoneyMovements { get; set; }
public virtual DbSet<EFCurrency> Currencies { get; set; }
}
public class EFWalletRepository : IWalletRepository {
private readonly EFDbContext _dataContext;
public EFWalletRepository(EFDbContext dataContext) {
_dataContext = dataContext ?? new EFDbContext();
}
public int SaveChanges() {
return _dataContext.SaveChanges();
}
public void Dispose() {
_dataContext.Dispose();
}
public void Create(IWallet wallet) {
...???
}
}
Теперь проблема: как я могу работать с интерфейсами, когда DataContext знает только о конкретных реализациях? Я делаю все это неправильно?
UPDATE:
ИТАК, в основном, как указано путем @TomTom, зачем бороться Entity Framework, когда вы могли бы просто принять свою власть? Думаю, я просто позволю EF быть абстракцией. Фактически, позволяя EF действовать как DAL, вы можете просто сосредоточиться на бизнес-логике своего проекта.
И все это вместе и отвечать на @tdragon относительно репозиториев/единицы работы вопроса: да, я мог либо обернуть несколько репозиториев внутри единицы работы или просто пусть DbContext единичной работы:
public class EFWalletRepository : IWalletRepository {
private readonly EFDbContext _dataContext;
public EFWalletRepository() {
_dataContext = new EFDbContext();
}
public void Dispose() {
_dataContext.Dispose();
}
public IEnumerable<Wallet> Wallets {
get { return _dataContext.Wallets; }
}
public void SaveWallet(Wallet wallet) {
if (wallet.Id == 0) {
_dataContext.Wallets.Add(wallet);
} else {
var databaseEntry = _dataContext.Wallets.Find(wallet.Id);
//update properties
}
_dataContext.SaveChanges();
}
}
Вы также абстрагируете данные; вы должны только отвлечь логику. Держите POCO в бизнес-слое. – Maarten