在三层架构中适当布局功能

本文关键字:布局 功能 三层 | 更新日期: 2023-09-27 18:16:23

我正在一个asp.net项目与oracle作为后端工作。最初,我使用三层架构开发这个应用程序,其中UI作为aspx页面,BLL和DAL作为类库项目。我在BLL和DAL中都使用了静态类和方法。DAL仅由单个类组成,具有静态方法Select, Execute和ExecuteScalar,这些方法接受BLL类转发的查询。

木豆

private static string connString = ""
private static OracleConnection conn;
public static OracleConnection OpenConn()
{
  if (conn==null)
  {
    conn = new OracleConnection(connString);
  }
  if (conn.State != ConnectionState.Open)
  {
    conn.Open();
  }
  return conn;
}
public static DataTable Select(string query)
{
  DataTable dt = new DataTable();
  OracleDataAdapter da = new OracleDataAdapter(query, OpenConn());
  da.Fill(dt);
  return dt;
}
public static void Execute(string query)
{
  OracleCommand cmd = new OracleCommand(query, OpenConn());
  cmd.ExecuteNonQuery();
}
public static int ExecuteScaler(string query)
{
  OracleCommand cmd = new OracleCommand(query, OpenConn());
  int id = Convert.ToInt32(cmd.ExecuteScalar());
  return id;
}

这个DAL被BLL类调用的方式如下所示员工BLL

public static DataTable GetEmployees(int facilityid)
    {
        DataTable dt = new DataTable();
        string q = string.Format("SELECT * FROM ..");
        dt = OraDAL.Select(q);
        return dt;
    }

    public static DataTable AddEmployee(string name, , int departmentid , int employeeType)
    {
        DataTable dt = new DataTable();
        string q = string.Format("INSERT INTO ...");
        dt = OraDAL.Select(q);
        return dt;
    }

现在我正在重构应用程序。与BLL和DAL相同的三层体系结构作为类库项目,另外还有一个名为Domain的类库项目,用于包含所有其他项目引用的域类。我使用这些类在层之间传输数据。这一次将DAL类保持为静态,将BLL保持为正常类。我已经将大部分功能(查询)移到了DAL中。现在DAL有了EmployeesDAL、DepartmentsDAL等类,以及包含Select、Execute和ExecuteScalar静态方法的泛型类。

Employee.cs

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Department department { get; set; }
    public EmployeeType employeeType { get; set; }
}

EmployeesDAL

public static List<Employee> GetEmployees(int departmentid)
    {
        if (departmentid > 0)
        {
            string query = string.Format("SELECT * FROM EMPLOYEES WHERE department='{0}')", departmentid);
            return GetCollection(OraDAL.Select(query));
        }
        return null;
    }
    public static Employee GetEmployee(int employeeid)
    {
        if (employeeid > 0)
        {
            string query = string.Format("SELECT * FROM PMS_EMPLOYEES WHERE Id='{0}'", employeeid);
            return GetSingle(OraDAL.Select(query));
        }
        throw new Exception("Employee id not valid");
    }
    public static int AddEmployee(Employee employee)
    {
        if (employee !=  null)
        {
            string query = string.Format("INSERT INTO PMS_EMPLOYEES (name, department, employee_type) VALUES ('{0}','{1}','{2}')", employee.Name, employee.department.Id, employee.employeeType.Id);
            return OraDAL.Execute(query);
        }
        throw new Exception("Values not valid");
    }
private static List<Employee> GetCollection(DataTable table)
    {
        List<Employee> employees = null;
        if (table != null)
        {
            if (table.Rows.Count > 0)
            {
                employees = new List<Employee>();
                foreach (DataRow row in table.Rows)
                {
                    employees.Add(ReadDataRow(row));
                }
            }
        }
        return employees;
    }
    private static Employee GetSingle(DataTable table)
    {
        if (table != null)
        {
            if (table.Rows.Count > 0)
            {
                DataRow row = table.Rows[0];
                return ReadDataRow(row);
            }
        }
        return null;
    }
    private static Employee ReadDataRow(DataRow row)
    {
        Employee employee = new Employee() 
        {
            Id=int.Parse(row["ID"].ToString()),
            Name=row["NAME"].ToString(),
            employeeType=EmployeeTypesDAL.GetEmployeeType(int.Parse(row["EMPLOYEE_TYPE"].ToString())),
            department=DepartmentsDAL.GetDepartment(int.Parse(row["DEPARTMENT"].ToString()))
        };
        return employee;
    }

EmployeesBLL.cs

 public class EmployeesBLL
{
    public List<Employee> GetEmployees(int departmentid)
    {
        if (departmentid > 0)
        {
            return EmployeesDAL.GetEmployees(departmentid);
        }
        return null;
    }
    public int AddEmployee(Employee employee)
    {
        if (employee != null)
        {
            return EmployeesDAL.AddEmployee(employee);
        }
        throw new Exception("Employee cannot be null");
    }

这篇文章越来越长,但我希望你对情况有一个更好的了解。我在新设计中遇到了一些问题,这让我问了一个问题,这是正确的做事方法吗?因为主要目标是避免在不同层之间来回移动数据表。虽然这种新的逻辑编码方式太耗时,但值得付出努力。业务层变得太薄了,因为它们提供的唯一服务似乎就是从DAL调用类似的方法,我首先需要BLL吗?如果有,在什么情况下需要单独的清单?

编辑

我在上述设计中注意到的一个问题是数据库调用的数量。由于在填充对象时也填充了所有子对象,因此调用太多,导致调用数据库。例如,填充Employee对象将导致填充department实例。在大多数情况下,我只需要部门id,而不是整个部门的信息。

在三层架构中适当布局功能

三层架构各部分的用途如下:

1。UI

允许用户与您的域模型交互

2。领域模型/中间层

包含您的特定领域或业务流程到代码的翻译。作为您的特定业务问题或环境的表示。这一层应该包含应用程序的所有业务规则和业务对象。

3。数据访问层

允许将域模型对象持久化到数据存储中并从数据存储中检索。数据访问层只是从持久数据存储(即数据库)中获取数据,并将其转换为领域模型对象,然后将领域模型对象持久化到数据存储中。

在这三个领域中,我认为最重要的领域是领域模型/中间层。这是应用程序的核心和灵魂,是应用程序实际解决特定业务问题并为将要使用您的软件的组织提供价值的地方。其他两个区域的目的仅仅是向用户公开您的领域模型(UI),或者允许它被检索或存储(数据层)。

这意味着您应该努力在领域模型/中间层上花费尽可能多的精力。这是你解决组织特定业务问题的地方,也是你可以真正为公司或客户增加价值的地方。

将这一一般原则应用于你的特殊情况,我有以下意见/建议。

  1. 您正在手动创建您的数据访问层和手工制作SQL语句。一般来说,这是一种非常低价值的时间利用。现在有很多对象关系映射器(ORM)工具,比如nHibernate或实体框架,它们负责从数据存储中加载域模型对象并将对象持久化回数据存储所需的底层管道。我觉得你应该调查一下这些。我认为使用这些ORM工具之一的解决方案将比您建议的任何一个选项都更好。

  2. 根据你发布的代码,你的领域模型/中间层只是一个属性包,没有业务逻辑或业务规则。如果情况确实如此,那就应该是这样。然而,这将是一个很好的利用您的时间与您的涉众交谈,并真正努力在领域模型中建模他们的过程,因为这是您可以最好地为您的组织增加价值的地方。

我知道这有点啰嗦,但希望对你有帮助。

表示层:

你已经知道了。这是你的UI。它由视图、视图模型和(控制器/呈现者)组成。这个表示层只有与UI相关的逻辑(定位、css样式等)。它不知道BLL(接口)的实现,也不知道DAL(存储)。

业务层

业务逻辑所在的位置。每个选择操作,计算,验证,插入操作,删除,更新操作都属于这里。它不知道UI,所以它可以在任何UI中工作,无论是web/桌面/移动应用程序,具有相同的业务逻辑。这意味着在层中,没有使用明显的缓存/会话。相反,您可以将其封装在某个接口中。它不知道存储,这意味着你需要另一个层来做存储,而是DAL

数据访问层

这一层只是对存储(平面文件、数据库、web服务、xml、json等)进行CRUD操作,并返回对象模型。这是所有。它不知道UI和业务规则。这一层的目的是使其易于更换。假设您需要将存储从数据库替换为xml,这是该层的工作,而不影响其他层。

回答你的问题

希望你已经知道3层的目的。

现在假设你在你的情况下使用3层的BLL:

  1. 对Employee存储的任何更改都不会影响BLL和UI
  2. 业务逻辑的任何更改(新的搜索参数)都会影响DAL
  3. 你的BLL不知道数据访问(连接/数据库上下文等),这意味着它根本不需要知道连接
  4. 在BLL
  5. 添加明显的映射

现在假设您使用的是没有BLL的2层:

  1. 员工存储的任何更改都不会影响UI(无BLL)
  2. 业务逻辑的任何更改(新的搜索参数)都会影响DAL
  3. 你的UI知道DAL。如果您将其设计为单独的项目,则会添加引用并打破分层。这是打开机会,你的UI直接访问其他DAL。

是的,在您的情况下使用BLL是相当无用的,因为您只有将UI和DAL分开才能获得好处。但这就是三级游戏的意义所在,不是吗?

也就是说,如果您正在使用存储过程select。您真正需要的是DAL中的通用存储库模式,它将在访问BLL时为您提供极大的帮助。