Прежде всего, извините, если это будет длинный пост, но я не знаю, как правильно объяснить проблему без необходимых деталей.
У меня проблемы с поиском способа абстрагировать мой 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 знает только о конкретных реализациях? Я все делаю неправильно?
ОБНОВЛЕНИЕ:
Хорошо, в общем, как заявил @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();
}
}