4

Прежде всего, мне жаль, если это будет длинный пост, но я не знаю, как правильно объяснить проблему без необходимых деталей.Отвлечься от реализации 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(); 
    } 
} 
+2

Вы также абстрагируете данные; вы должны только отвлечь логику. Держите POCO в бизнес-слое. – Maarten

ответ

3

Проще говоря: да, вы делаете это неправильно. Вы вводите плохую абстракцию (которая дорого стоит вам по функциональности) «из-за». EF уже является абстракцией.

Любая абстракция сверху этого будет стоить вам с точки зрения используемой функциональности - что с точки зрения баз данных имеет большое влияние на производительность. Хотите пример? «Включить» для предварительной загрузки свойств навигации (вместо ленивой загрузки). Вам придется обойти это и много более подробного поведения, характерного для ORM, - для получения чего-то? И если вы откажетесь от тех более высоких, более специфических функций, ваша производительность будет страдать.

+0

Я думаю, это просто зависит от его требований. Я не буду освещать эти функции, пока не буду нуждаться в них ЯГНИ. Главный вопрос: где главная ценность бизнеса? Имея более простой способ изменить dbms или иметь более легкое открытое окно для функций EF. EF - это только абстракция «полпути», поскольку она сильно зависит от самой технологии EF. это неплохо по умолчанию, но это зависимость. Я думаю, что оба пути возможны и должны быть проверены на соответствие требованиям. –

+0

Я не вижу этого таким образом. в моем случае я никогда не нуждался в этой функции EF, и большинство из них, возможно, никогда не нуждаются в них. Если эти функции очевидны, ваше право. но действительно ли они в его случае? Но ваш грубый пост чувствует себя немного странным и не очень профессиональным для меня ... Очень плохо реализовать все, чтобы бояться «может быть, через 10 лет мне может понадобиться». Если вы знаете, что вы * будете нуждаться в нем, тогда выполните его. Но, не зная его контекста, вы не можете знать. было бы лучше посоветовать ему подумать о том, что очень вероятно, что ему понадобится эта функция или спросить бизнесмена! –

+0

Хорошо, возможно, я должен был сказать это раньше, но этот проект, над которым я работаю, - это просто «домашнее задание», просто способ улучшить навыки проектирования, создав что-то с очень маленькой отправной точки. Конечно, этот проект вообще не нуждается в таком виде абстракции, причем в этом случае, когда EF является абстракцией как таковым, даже если это не так, как я представляю абстракцию. –

1

Я не вижу причин, чтобы отвлечь вашу модель (сущности). Вы ожидаете, что они изменятся, когда вы измените способ доступа к базе данных?

Но если вы хотите, чтобы сохранить его таким образом, вы можете сделать свой репозиторий интерфейсов родовое, и передать конкретный тип объекта при определении хранилища, так что вы бы в конечном итоге с:

public class EFWalletRepository : IWalletRepository<EFWallet> 
{ 
    public void Create(EFWallet wallet) 
    { 
     _dataContext.Add(wallet); 
    } 
} 

Другие предложения:

  1. Вы не должны раскрывать наборы для своих свойств модели. Это противоречит правилам ООП - вы должны скорее выявить некоторые методы для управления объектами, состояние должно быть более внутренним.
  2. Возможно, вам не нужно добавлять метод SaveChanges() в ваш репозиторий - это должно быть задание «единица работы» для фиксации всех изменений в базе данных.
  3. У вас возникнет проблема, если вы будете использовать более одного хранилища на своем уровне обслуживания, когда вы создадите новый репозиторий DbContext, когда у вас должен быть один для отдельной «единицы работы».
+0

Я абстрагирую сущности, потому что у EF есть свои декораторы, которые я не хотел включать в свою библиотеку DAL. '[Таблица (« кошелек »)] публичный класс Кошелек { [Key] [Столбец (" id ")] public long Id {get; задавать; } .... } ' –

+1

Вместо использования атрибутов для украшения ваших объектов вы можете использовать файлы конфигурации. Тогда вы, сущности, останетесь без EF и свободны, см. Здесь: http://www.entityframeworktutorial.net/code-first/fluent-api-in-code-first.aspx – tdragon