Введення залежностей за допомогою n-ярусного рішення Entity Framework


12

В даний час я розробляю n-ярусне рішення, яке використовує Entity Framework 5 (.net 4) в якості своєї стратегії доступу до даних, але мене хвилює питання про те, як включити введення залежності, щоб зробити його тестовим / гнучким.

Мій поточний макет рішення такий (моє рішення називається Alcatraz):

Alcatraz.WebUI : Проект веб-форми asp.net, інтерфейс для переднього користувача, посилання на проекти Alcatraz.Business та Alcatraz.Data.Models .

Alcatraz.Business : Бібліотечний проект класу, містить ділову логіку, посилання на проекти Alcatraz.Data.Access , Alcatraz.Data.Models

Alcatraz.Data.Access : проект бібліотеки класів, в якому розміщені AlcatrazModel.edmx і AlcatrazEntitiesDbContext, посилання на проекти Alcatraz.Data.Models .

Alcatraz.Data.Models : Проект бібліотеки класів, містить POCO для моделі Alcatraz, відсутні посилання.

Моє бачення того, як буде працювати це рішення, це те, що web-ui створить сховище в бізнес-бібліотеці, це сховище матиме залежність (через конструктор) рядка з'єднання (не AlcatrazEntitiesекземпляра). Веб-інтерфейс знав би рядки підключення до бази даних, але не те, що це був рядок з'єднання рамки об'єкта.

У бізнес-проекті:

public class InmateRepository : IInmateRepository
{
    private string _connectionString;

    public InmateRepository(string connectionString)
    {
        if (connectionString == null)
        {
            throw new ArgumentNullException("connectionString");
        }

        EntityConnectionStringBuilder connectionBuilder = new EntityConnectionStringBuilder();

        connectionBuilder.Metadata = "res://*/AlcatrazModel.csdl|res://*/AlcatrazModel.ssdl|res://*/AlcatrazModel.msl";
        connectionBuilder.Provider = "System.Data.SqlClient";
        connectionBuilder.ProviderConnectionString = connectionString;

        _connectionString = connectionBuilder.ToString();
    }

    public IQueryable<Inmate> GetAllInmates()
    {
        AlcatrazEntities ents = new AlcatrazEntities(_connectionString);

        return ents.Inmates;
    }
}

У веб-інтерфейсі:

IInmateRepository inmateRepo = new InmateRepository(@"data source=MATTHEW-PC\SQLEXPRESS;initial catalog=Alcatraz;integrated security=True;");

List<Inmate> deathRowInmates = inmateRepo.GetAllInmates().Where(i => i.OnDeathRow).ToList();

У мене є кілька пов'язаних питань щодо цього дизайну.

  1. Чи має такий дизайн навіть сенс з точки зору можливостей Entity Frameworks? Я чув, що рамка Entity вже використовує шаблон "Одиниця роботи", чи просто я додаю ще один шар абстрактного?

  2. Я не хочу, щоб мій веб-інтерфейс безпосередньо спілкувався з Entity Framework (або навіть посилався на це з цього приводу), я хочу, щоб весь доступ до бази даних проходив через бізнес-рівень, оскільки в майбутньому я буду мати кілька проектів, що використовують один і той же бізнес-рівень (веб-сервіс, додаток для Windows тощо), і я хочу, щоб це було просте обслуговування / оновлення, маючи бізнес-логіку в одній центральній області. Це відповідний спосіб досягти цього?

  3. Чи повинен рівень Business навіть містити сховища або вони повинні міститись у шарі доступу? Якщо там, де вони є в порядку, передається рядок з'єднання, яку слід припустити?

Дякуємо, що знайшли час для читання!

Відповіді:


11

Те, як ви робите DI, неправильно.

По-перше, рядок з'єднання належить до рівня даних. Або у файлі web.config.

Наступна абстракція, з якою ви матимете справу, - це DbContext, а не рядок з'єднання. Ваші сховища не повинні знати про рядки з'єднання. Ваша бізнес-логіка не буде знати про DbContext і т.д.

Ваш користувальницький інтерфейс не матиме жодного уявлення і не буде інстанціювати щось, що стосується EF.

Конкретні відповіді на ваші моменти:

  1. Не додайте абстракцій, поки ви не знайомі з EF. Це вже додає гарні абстракції, такі як UoW, запити, використання POCO тощо.

  2. Щоб DI працював, у вас є корінь Composition, який посилається на всі необхідні компоненти. Це може бути або не бути в проекті WebUI. Якщо це не так, слід очікувати, що він не посилається на EF або будь-яку іншу техніку, пов’язану з даними.

  3. Зупиніться тут. Перестаньте додавати абстракції над абстракціями. Почніть з прямої та «наївної» архітектури та розвивайте її з часом.

Абстракції - це інструмент боротьби зі складністю. Відсутність складності означає відсутність необхідних абстракцій (поки що).


Щоб було зрозуміло, що я розумію, що ви говорите: сховище (який інтерфейс існує в бізнесі, а конкретний існує в Alcatraz.Data.Access?) Приймає a DbContextяк свою залежність. У бізнес-класах залежність є сховищами. Для введення залежності я це роблю вручну (тому я розумію, що відбувається). Причиною, по якій я хочу мати змогу встановити рядок з'єднання, DbContextє те, що я використовую базування даних, тому в певних випадках мені потрібно мати структуру об'єкта для підключення до різних баз даних (тієї ж структури). Я вас правильно розумію?
Метью

З наданого вами коду, здається, ви зовсім не робите DI. Основна мета DI - звільнити вас і ваш код від управління залежностями. Я не можу уявити, що ви робите це ефективно вручну без контейнера DI.
Борис Янков

також тримайте свій розум відкритим із DI. я вже, для розваги, задав саме таке питання тут, а потім на іншому форумі, щоб отримати протилежні відповіді. DI - це візерунок, а не архітектура. Залежно від вашої мети ви можете вирішити використовувати його чи ні. Я використовую його, але не з тих причин, які більшість людей кажуть мені використовувати його.
Бастьєн Vandamme

4

Кілька швидких коментарів. Я особисто, ймовірно, не передав би рядок з'єднання. Якщо я щось спробував би створити інтерфейси, можливо, для сховищ і просто передати інтерфейси навколо? Запропонуйте сховищам реалізувати або відкрити інтерфейс IOW.

Таким чином, вона не повинна бути базою даних, яка реалізує ваші сховища. вони можуть бути кешем пам'яті чи будь-чим іншим. Може, тоді ви могли б використовувати якусь структуру ін'єкційних залежностей, щоб придумати їх навіть?

Отже, відповідаючи на деякі ваші запитання:

  1. Так, я думаю, що це нормально
  2. Я все одно матиму посилання на інтерфейс користувача на проект EF та на еталонні інтерфейси рівня шару, які реалізує рівень сховища EF. Таким чином, інші проекти все-таки можуть використовувати ті самі збірки, але вони мають гнучкість замінити за бажанням?
  3. хммм, напевно, сховища у рівні доступу, але реалізують визначення інтерфейсу, відкритого в бізнес-шарі ??

Це лише деякі думки, які потрібно продумати.


Щодо пункту 2, я намагався досягти однієї мети - не мати CRUD безпосередньо в шарі ui. Що я маю на увазі, це те, що я хочу переконатися, що тільки CRUD може статися, пройшовши бізнес-рівень, таким чином, яким ним керують.
Матвій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.