Объектно-ориентированный дизайн n-tier. Я абстрагирую слишком много? Или недостаточно?

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

Я пытаюсь создать свои веб-формы asp.net (в C#) приложение как n-tier приложение. Я создал Уровень доступа к данным с помощью XSD набор данных со строгим контролем типов, который взаимодействует через интерфейс с бэкендом SQL-сервера. Я получаю доступ к DAL через некоторые Бизнес-Расположенные на слое объекты, которые я создал на 1:1 основание к таблицам данных в наборе данных (например, класс UsersBLL для Пользовательской таблицы данных в наборе данных). Я делаю проверки в BLL, чтобы удостовериться, что данные, переданные DAL, следуют бизнес-правилам приложения. Это - все хорошо и хороший. Где я застреваю, хотя точка, в которой я подключаю BLL к уровню представления. Например, мой класс UsersBLL имеет дело главным образом с целыми таблицами данных, поскольку он взаимодействует через интерфейс с DAL. Я должен теперь создать отдельного "Пользователя" (Исключительный) класс, который планирует свойства отдельного пользователя, а не многочисленных пользователей? Таким образом, я не должен делать никакого поиска таблиц данных на уровне представления, поскольку я мог использовать свойства, созданные в Пользовательском классе. Или было бы лучше так или иначе попытаться обработать эту внутреннюю часть UsersBLL?

Извините, если это звучит немного сложным... Ниже код от UsersBLL:

using System;
using System.Data;
using PedChallenge.DAL.PedDataSetTableAdapters;

[System.ComponentModel.DataObject]
public class UsersBLL
{
    private UsersTableAdapter _UsersAdapter = null;
    protected UsersTableAdapter Adapter
    {
        get
        {
            if (_UsersAdapter == null)
                _UsersAdapter = new UsersTableAdapter();

            return _UsersAdapter;
        }
    }


    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, true)]
    public PedChallenge.DAL.PedDataSet.UsersDataTable GetUsers()
    {
        return Adapter.GetUsers();
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, false)]
    public PedChallenge.DAL.PedDataSet.UsersDataTable GetUserByUserID(int userID)
    {
        return Adapter.GetUserByUserID(userID);
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, false)]
    public PedChallenge.DAL.PedDataSet.UsersDataTable GetUsersByTeamID(int teamID)
    {
        return Adapter.GetUsersByTeamID(teamID);
    }


    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, false)]
    public PedChallenge.DAL.PedDataSet.UsersDataTable GetUsersByEmail(string Email)
    {
        return Adapter.GetUserByEmail(Email);
    }


    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Insert, true)]
    public bool AddUser(int? teamID, string FirstName, string LastName, 
        string Email, string Role, int LocationID)
    {
        // Create a new UsersRow instance
        PedChallenge.DAL.PedDataSet.UsersDataTable Users = new PedChallenge.DAL.PedDataSet.UsersDataTable();
        PedChallenge.DAL.PedDataSet.UsersRow user = Users.NewUsersRow();

        if (UserExists(Users, Email) == true)
            return false;


        if (teamID == null) user.SetTeamIDNull();
        else user.TeamID = teamID.Value;
        user.FirstName = FirstName;
        user.LastName = LastName;
        user.Email = Email;
        user.Role = Role;
        user.LocationID = LocationID;

        // Add the new user
        Users.AddUsersRow(user);
        int rowsAffected = Adapter.Update(Users);

        // Return true if precisely one row was inserted,
        // otherwise false
        return rowsAffected == 1;
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Update, true)]
    public bool UpdateUser(int userID, int? teamID, string FirstName, string LastName,
        string Email, string Role, int LocationID)
    {
        PedChallenge.DAL.PedDataSet.UsersDataTable Users = Adapter.GetUserByUserID(userID);
        if (Users.Count == 0)
            // no matching record found, return false
            return false;

        PedChallenge.DAL.PedDataSet.UsersRow user = Users[0];

        if (teamID == null) user.SetTeamIDNull();
        else user.TeamID = teamID.Value;
        user.FirstName = FirstName;
        user.LastName = LastName;
        user.Email = Email;
        user.Role = Role;
        user.LocationID = LocationID;

        // Update the product record
        int rowsAffected = Adapter.Update(user);

        // Return true if precisely one row was updated,
        // otherwise false
        return rowsAffected == 1;
    }

    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Delete, true)]
    public bool DeleteUser(int userID)
    {
        int rowsAffected = Adapter.Delete(userID);

        // Return true if precisely one row was deleted,
        // otherwise false
        return rowsAffected == 1;
    }

    private bool UserExists(PedChallenge.DAL.PedDataSet.UsersDataTable users, string email)
    {
        // Check if user email already exists
        foreach (PedChallenge.DAL.PedDataSet.UsersRow userRow in users)
        {
            if (userRow.Email == email)
                return true;
        }
        return false;
    }
}

Некоторое руководство в правильном направлении значительно ценилось бы!!

Спасибо все!

Max

7
задан max 8 June 2010 в 13:58
поделиться

2 ответа

Тип расслоения, который вы пытаетесь использовать, обычно включает отход от подхода DataTable к чему-то, что использует экземпляр (примерно) для каждой строки в базе данных.Другими словами, DAL вернет либо одного пользователя, либо коллекцию пользователей, в зависимости от того, какой статический метод Load вы вызываете. Это означает, что все методы, которые принимают набор параметров для представления пользователя, вместо этого будут принимать User DTO.

DAL для пользователей будет выглядеть примерно так:

public static class UserDal
{
    public static User Load(int id) { }

    public static User Save(User user) } { }

    public static IEnumerable<User> LoadByDiv(int divId) { }
}
  1. Он статичен, потому что у него нет состояния. (Возможно, у него могла быть база данных соединение как его состояние, но это в большинстве случаев не лучшая идея, и пул соединений удаляет все выгода. Другие могут поспорить за одноэлементный шаблон.)

  2. Он работает на уровне пользователя. Класс DTO, а не DataTable или любой другой другая специфическая для базы данных абстракция. Возможно, в реализации используется база данных, возможно, она использует LINQ: вызывающий абонент в любом случае не должен знать. Обратите внимание, как он возвращает IEnumerable вместо того, чтобы совершать какие-либо особый вид коллекции.

  3. Это касается только доступа к данным, не бизнес-правила. Следовательно, следует можно звонить только внутри компании логический класс, который работает с пользователями. Такой класс может решить, какой уровень доступа вызывающему разрешено иметь, если таковые имеются.

  4. DTO означает объект передачи данных, который обычно составляет класс, содержащий только общественная собственность. Вполне может быть грязный флаг, который автоматически устанавливается, когда свойства изменены. Может быть способ явно установить грязный флаг, но нет публичного способа очистить Это. Кроме того, идентификатор обычно доступен только для чтения (поэтому что его можно заполнить только из десериализация).

  5. DTO намеренно не содержит бизнес логика, которая пытается гарантировать правильность; вместо, соответствующий класс бизнес-логики - это то, что контекстно обеспечивает соблюдение правил. Бизнес-логика изменений, поэтому, если DTO или DAL были обременены это нарушение единоначалия принцип приведет к таким бедствиям, как не возможность десериализовать объект, потому что его значения больше не считаются законными.

  6. Уровень представления может создавать экземпляр пользователя. объект, заполните его и задайте слой бизнес-логики , чтобы вызвать метод Save в DAL. Если BLL выберет это, он заполнит идентификатор и снимите грязный флаг. Используя этот идентификатор, BLL может затем получить сохраненные экземпляры, вызвав Метод DAL Load-by-ID.

  7. В DAL всегда есть метод сохранения и идентификатор загрузки. метод, но он вполне может иметь методы загрузки на основе запросов, например, в приведенном выше примере LoadByDiv. Он должен предложить какие бы методы ни требовал BLL для эффективного операция.

  8. Реализация DAL является секретом, поскольку BLL и выше затронуты. Если поддержка база данных, обычно будут хранимые процедуры соответствующие различным методам DAL, но это деталь реализации. Точно так же и любой своего рода кеширование.

4
ответ дан 7 December 2019 в 07:40
поделиться

Чтобы упростить разработку, вы определенно не хотите извлекать целые таблицы данных и искать в них на уровне представления. Прелесть базы данных в том, что она индексируется, чтобы облегчить быстрый запрос данных на уровне строки (т. Е. Получить строку по индексированному идентификатору).

Ваш DAL должен предоставлять такой метод, как GetUserByUserID (int userID). Затем вы должны предоставить этот метод через BLL, обеспечив выполнение любой необходимой бизнес-логики.

Кроме того, я бы держался подальше от наборов данных типов и рассмотрел инструмент ORM, такой как Entity Framework.

3
ответ дан 7 December 2019 в 07:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: