2012-03-18 62 views
6

Một số bối cảnh: Đây gắn liền với mong muốn vừa chớm nở của tôi để xây dựng các ứng dụng web đa với: tạoLàm cách nào để thiết kế một lớp có chứa các thuộc tính từ các bảng tra cứu?

  1. C# ASP.NET web
  2. C# POCO kinh doanh đối tượng
  3. Một số loại Dal ... SQL (hoặc có lẽ EF4 nếu tôi có thể tìm ra)

Tôi thực sự không muốn một câu trả lời có lớp trình bày của tôi nói trực tiếp với các thực thể EF chẳng hạn.

Tôi đã thực hiện phát triển web của riêng mình với C# ASP.NET & SQL trong 10 năm nhưng tôi vẫn là tổng số tân binh khi nói đến OOAD chính thức. Tôi đã theo đuổi kỹ năng này với một niềm đam mê gần đây, nhưng tôi vẫn còn mới ở đó và có một cái gì đó tôi không thể hoàn toàn quấn quanh đầu tôi. Tôi hy vọng ai đó có thể giải thích nó theo một cách mà mang lại một sự hiển linh:

Hãy nói rằng tôi có thể tạo một ứng dụng web quản lý dân một cách nào đó, và đối tượng Person phải có một tài sản như FirstName, LastName, HairColor, EyeColor, dân tộc và tỉnh, vv tôi đang sử dụng SQL server cho persistence ... do đó, cảm giác chung sẽ ra lệnh rằng các lĩnh vực tương ứng trong bảng mọi người tất cả các phím nước ngoài:

FirstName varchar(50) 
LastName varchar(50) 
HairColor tinyint 
EyeColor tinyint 
Ethnicity tinyint 
StateOrProvince tinyint 

rõ ràng điều này có nghĩa rằng Tôi có bảng tra cứu tương ứng cho từng trường (ví dụ bảng HairColors, bảng EyeColors, bảng Dân tộc, v.v ...) và mỗi bảng tra cứu này có ID và một tên e. Tất nhiên trường Name trong các bảng tra cứu này sẽ được JOIN với dữ liệu People của tôi bất cứ khi nào tôi muốn hiển thị bất cứ điều gì hữu ích về một Person.

Một số tính năng chính của trang web sẽ là:

1.) dân liệt kê trong một GridView (FirstName, LastName, HairColor, EyeColor, Dân tộc và tỉnh)

2.) Hiện chi tiết của từng cá nhân trên trang chỉ đọc (FirstName, LastName, HairColor, EyeColor, Ethnicity, StateOrProvince)

3.) Cho phép người dùng cập nhật dữ liệu của từng cá nhân trên một trang cập nhật (FirstName, LastName, HairColor, EyeColor, Dân tộc và tỉnh)

Case # 1 Nếu tôi đã liệt kê một tập hợp các đối tượng Person trong một GridView ... mỗi trường hợp Người sẽ cần phải hiển thị của nó Thuộc tính HairColor, EyeColor, Ethnicity, StateOrProvince là các chuỗi có ý nghĩa (ví dụ: trường Tên từ bảng tra cứu SQL, không phải là ID của nó). Rõ ràng SQL sproc của tôi sẽ có một số JOIN để cung cấp cho tôi dữ liệu chuỗi thích hợp mà tôi cần để điền vào các thuộc tính văn bản này trong mỗi cá thể Person.

Case # 2 Again sproc của tôi sẽ có lệnh JOIN để mang lại những tên thuộc tính có thể đọc được con người như chuỗi, và tôi sẽ hiển thị chúng trong chỉ đọc khiển Label sử dụng một cái gì đó giống như myPerson.HairColor, myPerson.EyeColor , v.v.

Trường hợp # 3 Ở đây tôi sẽ hiển thị một trang có danh sách thả xuống cho từng thuộc tính này (ví dụ: giá trị = HairColorId, Text = HairColorName). Bản năng tức thời của tôi ở đây sẽ là sử dụng các ID của mỗi thuộc tính (giống như myPerson.HairColorId) để lặp qua các mục DDL và chọn một giá trị đại diện cho màu tóc mà bảng Mọi người hiện đang nắm giữ cho Người này. Nếu người dùng đã chọn một cái gì đó khác trong bất kỳ DDL thuộc tính nào, tôi cần chuyển các giá trị SelectedId thích hợp cho một sproc UPDATE và sửa đổi các giá trị trong bảng Mọi người cho Người cụ thể này.

Vì vậy mà dẫn tôi đến câu hỏi cuối cùng:

Làm thế nào để thiết kế tốt nhất một đối tượng Person như vậy mà nó chứa cả ID và Name cho HairColor, EyeColor, Dân tộc và tỉnh để tôi có thể sau đó sử dụng Tên khi hiển thị thông tin, nhưng ID để khởi chạy cập nhật điều khiển DDL ... và cuối cùng xử lý cập nhật?

Như tôi đã phản ánh về điều này ... Tôi đã đi đến kết luận rằng tôi cần tạo các lớp để đại diện cho các thuộc tính HairColor, EyeColor, Ethnicity, StateOrProvince.

Sau đó, lớp người của tôi, thay vì là một cái gì đó như thế này:

public class Person 
{ 
    string FirstName { get; set; } 
    string LastName { get; set; } 

    int HairColorId { get; set; } 
    string HairColorName { get; set; } 

    int EyeColorId { get; set; } 
    string EyeColorName { get; set; } 

    int StateOrProvinceId { get; set; } 
    string StateOrProvinceName { get; set; } 
    string StateOrProvinceCode { get; set; } 
} 

thay vào đó sẽ mở rộng sang một cái gì đó như thế này:

public class HairColor 
{ 
    int Id { get; set; } 
    string Name { get; set; } 
} 

public class EyeColor 
{ 
    int Id { get; set; } 
    string Name { get; set; } 
} 

public class StateOrProvince 
{ 
    int Id { get; set; } 
    string Name { get; set; } 
    string Code { get; set; } 
} 

public class Person 
{ 
    HairColor HairColor { get; set; } 
    EyeColor EyeColor { get; set; } 
    StateOrProvince StateOrProvince { get; set; } 

    public Person() 
    { 
     // how do I initialize a Person from a SQL data row? 

    } 
} 

Nhưng sau đó nếu lớp người của tôi không giống như ở trên ... làm thế nào trên trái đất để tôi khởi tạo tốt nhất nó (cho dù cá nhân hoặc trong một bộ sưu tập) từ một hàng nhất định của dữ liệu tôi lấy lại từ một truy vấn SQL? Tôi dường như nhớ lại rằng tôi không nên làm mới những thứ trong một nhà xây dựng (tức là this.HairColor = new HairColor (dr ["HairColorId"), dr ["HairColorName"];) ... vì vậy tôi tự hỏi làm thế nào một hãy gọi tới số

public static IEnumerable<Person> GetPeople() 
{ 
    ... 
} 

trong BLL của tôi có thể điền vào mỗi người dùng dữ liệu trước khi thêm vào bộ sưu tập không?

Thực sự hy vọng ai đó có thể cho tôi một khoảnh khắc "a ha" ở đây ...

Trả lời

2

Tôi nghĩ bạn có phương pháp phù hợp, tạo lớp học cho các thực thể hỗ trợ đó (mặc dù tôi đặt StateOrProvince trong thực thể Address riêng biệt và có thể tất cả những đặc điểm đó trong thực thể PersonTraits riêng biệt).

Có nhiều cách để giải quyết vấn đề này. Nếu không có ORM, hãy xem Data Mappers (cũng tại Dependent Mapping), có thể được sử dụng để ánh xạ từ truy vấn cơ sở dữ liệu đến một cá thể Person. Đây là một phác thảo của mã mapper: (. Bạn cũng có thể sử dụng một số loại riêng biệt Object Builder)

var row = ... // query database 
var person = new Person(row["FirstName"], row["LastName"]); 
person.EyeColor = new EyeColor(row["EyeColorID"], row["EyeColorName"]); 
... 

Bất cứ lúc nào bạn cập nhật một người, bạn nên cập nhật tất cả các thông tin hỗ trợ cũng sử dụng ID của các thực thể liên quan.

CẬP NHẬT: ORM như EF4 rất mạnh và sẽ giúp bạn thực hiện nhiều tác vụ lặp lại (như ánh xạ mà tôi đã mô tả). Điều quan trọng là giữ cho kiến ​​trúc của bạn linh hoạt và có độ bền vững chỉ như một lớp có thể thay thế được. Hãy xem here để được hướng dẫn. Ngoài ra, tôi thấy rằng cuốn sách "Thiết kế điều khiển tên miền" thực sự quan trọng để hiểu loại phân tách này và cách mô hình hóa các thực thể của bạn.

+0

Cảm ơn bạn. Đóng gói StateOrProvince trong một lớp Địa chỉ là đúng trên tiền.Tôi nghĩ đó sẽ là bước hợp lý tiếp theo của tôi khi tôi thực sự bắt đầu xây dựng nó. Tôi không bao giờ có thể nghĩ rằng đi một bước xa hơn với "PersonTraits" mặc dù bởi vì nó là một bước tiến xa khỏi lược đồ DB. Tôi đoán tôi quá quen với việc suy nghĩ về mô hình SQL của mình nên tôi không thể giải phóng suy nghĩ của mình để suy nghĩ trong một mô hình đối tượng. – octechnologist

+0

Bạn có đề xuất sử dụng ORM không? Tôi đã nhầm lẫn với EF4 với tư cách là một DAL ở một địa điểm thử nghiệm trước đây khoảng 6 tháng trước ... nhưng tôi không nghĩ rằng tôi khá sẵn sàng về mặt tinh thần. Tôi gần như đi đến một điểm với sự hiểu biết của tôi về OOP rằng nó có thể có ý nghĩa hơn với tôi bây giờ. – octechnologist

+1

Chắc chắn, một ORM như EF4 là rất mạnh mẽ và sẽ giúp bạn với rất nhiều nhiệm vụ lặp đi lặp lại (như bản đồ tôi đã mô tả). Điều quan trọng là giữ cho kiến ​​trúc của bạn linh hoạt và có độ bền vững chỉ như một lớp có thể thay thế được. Hãy xem [tại đây] (http://blogs.msdn.com/b/adonet/archive/2009/05/21/poco-in-the-entity-framework-part-1-the-experience.aspx) cho một số hướng dẫn. Ngoài ra, tôi thấy rằng cuốn sách "Thiết kế điều khiển tên miền" thực sự quan trọng để hiểu loại phân tách này và cách mô hình hóa các thực thể của bạn. –

1

Tôi sẽ phản ánh các bảng tra cứu của bạn dưới dạng enums. Sau đó, bạn nhận được cả id và tên trong một giá trị duy nhất. Nếu tên bao gồm các ký tự không thể được sử dụng trong số nhận dạng thì bạn có thể dễ dàng tạo thuộc tính để xử lý dữ liệu bổ sung.

Thông tin cá (ví dụ Ví dụ Mã, sửa đổi cho phù hợp, tôi viết trong VB để chuyển đổi sang C# sẽ nessecary):

Namespace Company.Data 
    Public Enum EyeColor As Int16 
    Unknown = 0 
    Brown = 1 
    Blue = 2 
    Green = 3 
    End Enum 

    Public Enum HairColor As Int16 
    Unknown = 0 
    Brown = 1 
    Blond = 2 
    Red = 3 
    Pink = 4 
    End Enum 
End Namespace 



Public Class Person 

    Public Property EyeColor As EyeColor = EyeColor.Unknown 

    Public Property HairColor As HairColor = HairColor.Unknown 

End Class 

Vì bạn đang sử dụng enums bản đồ các giá trị enum cá nhân để cơ sở dữ liệu của bạn tra cứu các phím của bảng. Vì vậy, bạn có thể nhận được Hiển thị với aPersonObject.HairColor.ToString() và bạn có thể lấy ID của mình với aPersonObject.HairColor

Bạn có thể thực sự ưa thích và sử dụng một số mã-gen (mẫu t4 mabey) để tạo enums của bạn tự động từ các giá trị trong cơ sở dữ liệu.

+0

Tôi thực sự đánh giá cao ý kiến ​​của bạn nhưng tôi quá ngớ ngẩn để hiểu nó vào lúc này. Tôi đã sử dụng enums ... nhưng chủ yếu chỉ là hằng số cho các quyết định tuyên bố Case. Có cách nào bạn có thể đưa ra phản hồi của bạn để có một mã mẫu nhỏ có thể lật công tắc "a ha" của tôi không? Nếu tôi có tệp Person.cs và tệp PersonManager.cs chứa các phương thức tĩnh như GetPeople() hoặc GetPerson() ... thì các enums này sẽ ở đâu ... và chúng sẽ tích hợp với lớp Person của tôi như thế nào? – octechnologist

+0

đã thêm một số nội dung bổ sung. Nếu bạn cần làm rõ thêm, hãy cho tôi biết. –

+0

Toàn bộ điểm của khóa ngoại là danh sách được chứa trong kho dữ liệu chứ không phải bìa cứng. –

1

Bạn đã xem xét "thuộc tính điều hướng" trong EF chưa? Nó sẽ cho phép bạn giữ các ID trong lớp chính (ví dụ: Person) và tham chiếu các thuộc tính chuỗi thông qua các thuộc tính điều hướng. Ví dụ, bạn sẽ có:

Person p = [có được kỷ lục từ bối cảnh dữ liệu EF]

p.state_id sẽ tham khảo các ID số của nhà nước trong khi p.State.Name sẽ là tên chuỗi của nhà nước. EF chăm sóc tải hồ sơ nhà nước tham chiếu. Nó thậm chí có thể tạo chúng cho bạn tự động nếu bạn sử dụng cơ sở dữ liệu đầu tiên và có khóa ngoài được xác định (có các công cụ sẽ chuyển đổi cơ sở dữ liệu thành mã đầu tiên)

+0

Tôi khá chắc chắn điều này sẽ có lớp trình bày của tôi nói chuyện trực tiếp với các thực thể EF, phải không? Tôi thích tránh điều đó như tôi đã đề cập ở phần đầu của câu hỏi (khu vực ngữ cảnh). Từ nghiên cứu tôi đã thực hiện tôi đã chắc chắn rằng đó là một thực hành tốt nhất cho lớp kinh doanh của tôi là một trừu tượng ra khỏi lớp kiên trì. Trình bày -> kinh doanh -> kiên trì. Tôi nghĩ rằng hành động của tôi đang cố gắng sử dụng các ID SQL phá vỡ mô hình này ... nhưng nó không phải là "xấu" như lớp trình bày của tôi nói chuyện trực tiếp với các thực thể? Tôi không có chuyên gia rõ ràng ... nhưng đó là những gì tôi thu thập. – octechnologist

+0

Có, bạn có thể yêu cầu họ nói chuyện với các thực thể EF tuy nhiên với mã đầu tiên, các thực thể EF của bạn chỉ là các lớp POCO không khác gì nếu bạn đã tự viết chúng. Vâng, bạn có thể tạo ra một hệ thống phân cấp đầy đủ các lớp ở lớp trình bày của bạn nhưng tại sao làm điều đó khi các lớp trình bày sẽ được * chính xác * giống như các thực thể POCO EF. Bạn có thể đặt các lớp học EF POCO vào một hội đồng riêng biệt và có đó là phương tiện trao đổi dữ liệu btw tất cả các lớp khác nhau. – Tundey

+0

Hãy xem công cụ này để tạo POCO từ EDMX: http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d – Tundey

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