2010-06-08 29 views
7

Tôi đang xây dựng giải pháp cấp doanh nghiệp đầu tiên của mình (ít nhất tôi đang cố gắng để làm cho nó cấp doanh nghiệp). Tôi đang cố gắng làm theo các mẫu thiết kế thực hành tốt nhất nhưng tôi bắt đầu lo lắng rằng tôi có thể đi quá xa với sự trừu tượng.Thiết kế n-tier hướng đối tượng. Tôi có trừu tượng quá nhiều không? Hay không đủ?

Tôi đang cố gắng tạo ứng dụng web asp.net (trong C#) dưới dạng ứng dụng n-tier. Tôi đã tạo ra một Lớp truy cập dữ liệu bằng cách sử dụng một tập dữ liệu được đánh giá mạnh XSD có giao diện với một phần cuối máy chủ SQL. Tôi truy cập vào DAL thông qua một số đối tượng lớp kinh doanh mà tôi đã tạo trên cơ sở 1: 1 cho các datatables trong tập dữ liệu (ví dụ, một lớp UsersBLL cho Users datatable trong tập dữ liệu). Tôi đang kiểm tra bên trong BLL để đảm bảo rằng dữ liệu được chuyển đến DAL tuân theo các quy tắc kinh doanh của ứng dụng. Đó là tất cả tốt và tốt. Tôi đang gặp khó khăn mặc dù là điểm mà tại đó tôi kết nối BLL với lớp trình bày. Ví dụ, lớp UsersBLL của tôi giao dịch chủ yếu với toàn bộ datatables, vì nó giao tiếp với DAL. Tôi có nên tạo một lớp "Người dùng" (Singular) riêng biệt để ánh xạ các thuộc tính của một người dùng, thay vì nhiều người dùng không? Bằng cách này, tôi không phải thực hiện bất kỳ tìm kiếm nào thông qua các datatables trong lớp trình bày, vì tôi có thể sử dụng các thuộc tính được tạo trong lớp User. Hoặc nó sẽ là tốt hơn bằng cách nào đó cố gắng xử lý này bên trong UsersBLL?

Xin lỗi nếu điều này nghe có vẻ hơi phức tạp ... Dưới đây là mã từ 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; 
    } 
} 

Một số hướng dẫn đi đúng hướng sẽ được đánh giá rất nhiều !!

Cảm ơn tất cả!

Max

Trả lời

4

Các loại layering bạn đang cố gắng để thường liên quan đến việc di chuyển ra khỏi cách tiếp cận DataTable để một cái gì đó mà sử dụng một ví dụ cho (khoảng) mỗi hàng trong cơ sở dữ liệu. Nói cách khác, DAL sẽ trả về một User hoặc một tập hợp Users, tùy thuộc vào phương thức Load tĩnh mà bạn gọi. Điều này có nghĩa là tất cả các phương thức lấy một loạt tham số để đại diện cho người dùng thay vào đó sẽ chấp nhận User DTO.

Một Dal cho người sử dụng sẽ giống như thế này:

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

    public static User Save(User user) } { } 

    public static IEnumerable<User> LoadByDiv(int divId) { } 
} 
  1. Đó là tĩnh bởi vì nó không có nhà nước. (Có thể cho rằng, nó có thể có một kết nối cơ sở dữ liệu như trạng thái của nó, nhưng đó là không phải là một ý tưởng tốt trong hầu hết các trường hợp, và kết nối tổng hợp loại bỏ bất kỳ lợi ích . Những người khác có thể tranh luận cho một mẫu singleton .)

  2. Nó hoạt động ở cấp độ của lớp User DTO, không phải DataTable hoặc bất kỳ trừu tượng cụ thể cho cơ sở dữ liệu khác. Có lẽ việc triển khai sử dụng cơ sở dữ liệu , có lẽ nó sử dụng LINQ: người gọi không cần biết cả hai cách. Lưu ý cách trả về số IEnumerable thay vì cam kết cho bất kỳ loại bộ sưu tập cụ thể nào theo số .

  3. Chỉ liên quan đến truy cập dữ liệu, không phải là quy tắc kinh doanh. Do đó, cần chỉ có thể gọi từ bên trong một lớp học kinh doanh giao dịch với người dùng. một lớp học có thể quyết định mức truy cập nào người gọi được phép có, nếu có.

  4. DTO là viết tắt của Đối tượng chuyển dữ liệu, trong đó thường là số tiền cho một lớp chỉ chứa thuộc tính công khai. Nó cũng có thể có một cờ bẩn được tự động đặt khi thuộc tính được thay đổi. Có thể có cách để khám phá đặt cờ bẩn, nhưng không có cách nào công khai để xóa nó. Ngoài ra, ID thường là chỉ đọc (vì vậy rằng ID này chỉ có thể được điền từ deserialization).

  5. DTO cố ý không chứa doanh nghiệp logic cố gắng đảm bảo tính chính xác; thay vào đó, lớp logic kinh doanh tương ứng là những gì quy tắc thực thi theo ngữ cảnh. Logic kinh doanh thay đổi, vì vậy nếu DTO hoặc DAL bị gánh nặng với , vi phạm trách nhiệm nguyên tắc sẽ dẫn đến thảm họa như không có thể deserialize đối tượng vì giá trị của nó không còn được coi là hợp pháp.

  6. Lớp trình bày có thể khởi tạo đối tượng User , điền vào và yêu cầu lớp logic nghiệp vụ để vui lòng gọi phương thức Lưu trong DAL. Nếu BLL chọn làm điều này, nó sẽ điền ID và xóa cờ bẩn. Bằng cách sử dụng ID này, BLL có thể sau đó truy xuất các phiên bản được lưu giữ bằng cách gọi phương thức tải theo phương thức tải của DAL theo phương thức của DAL.

  7. DAL luôn có phương thức Lưu và phương pháp tải theo ID , nhưng cũng có thể có phương pháp tải dựa trên truy vấn, chẳng hạn như ví dụ LoadByDiv ở trên. Nó cần phải cung cấp bất kỳ phương pháp nào mà BLL yêu cầu cho hoạt động hiệu quả .

  8. Việc triển khai DAL là bí mật theo như BLL trở lên có liên quan. Nếu sự ủng hộ là một cơ sở dữ liệu , thường sẽ có các thủ tục được lưu trữ tương ứng với các phương pháp DAL khác nhau, nhưng đây là chi tiết triển khai. Trong cùng một cách, do đó, bất kỳ loại bộ nhớ đệm nào là .

+0

Cảm ơn Steven. Chỉ cần làm rõ, bạn có nghĩa là tôi sẽ nhận được DAL để trả về một UserRow đơn chứ không phải toàn bộ DataTable? Ngoài ra, bạn có thể mô tả thêm về phương pháp tải tĩnh không? Cảm ơn! – max

+0

@max: Vui lòng cho tôi biết nếu tôi có thể làm rõ thêm. –

+0

@Steven: Cảm ơn bạn đã làm rõ.Vì vậy, cách tôi hiểu phân lớp như sau (từ DB sang UI): 1) Lớp trừu tượng cơ sở dữ liệu, ví dụ: XSD, LINQ, v.v. * Bao gồm ~ 2 phương pháp - GetUser, GetUsers -> Điền DTO người dùng (a Lớp người dùng đơn giản?) 2) Lớp tĩnh UserDAL mà bạn đã nêu ở trên nhận được User DTO và tạo bộ sưu tập. 3) UserBLL gọi UserDAL của bạn để nhận đối tượng người dùng. 4) Trình diễn lớp gọi UserBLL Điều này có đúng không? Vẫn cố gắng để có được đầu của tôi xung quanh nó. Cảm ơn! – max

3

Để tạo điều kiện cho thiết kế của bạn, bạn chắc chắn không muốn kéo toàn bộ bảng dữ liệu và tìm kiếm trong bảng trình bày. Vẻ đẹp của cơ sở dữ liệu là nó được lập chỉ mục để tạo điều kiện truy vấn nhanh dữ liệu cấp hàng (tức là nhận hàng bằng số nhận dạng được lập chỉ mục).

DAL của bạn nên hiển thị phương thức như GetUserByUserID (int userID). Sau đó, bạn nên trưng ra phương thức đó thông qua BLL, thực thi bất kỳ logic nghiệp vụ cần thiết nào.

Ngoài ra, tôi sẽ xóa các Bộ dữ liệu loại và xem xét một công cụ ORM chẳng hạn như khung thực thể.

+0

Cảm ơn Matthew! Phương thức DAL GetUserByUserID (int userID) loại nào sẽ trả về? Ngoài ra, BLL sẽ trả về cùng một loại sau khi nó được thực hiện thực thi logic nghiệp vụ? Ngoài ra, trên một chút tiếp tuyến, BLL có thể được tạo tự động bởi Visual Studio không? Cảm ơn! – max

+1

Ngoài ra, nếu bạn đơn giản có phương thức GetUserById (int id), nó rất hữu ích nếu bạn muốn chèn một lớp đệm mà không thay đổi bất kỳ phương thức front-end hoặc kiến ​​trúc chung nào. –

+1

@max: Entity Framework sẽ tự động tạo DAL; bạn vẫn phải viết BLL vì, đây là logic kinh doanh của bạn. Entity Framework sẽ xử lý serializing/deserializing DTO. Ngoài ra, quyền của Ed về bộ nhớ đệm có khả năng hữu ích. Tuy nhiên, nó có thể là một biến chứng nghiêm trọng, về mặt đảm bảo tính chính xác. –

Các vấn đề liên quan