MVC筆記 用Model創建數據模型


    所有需要進行數據訪問的操作都須依賴Model提供的服務。簡單地說,Model負責通過數據庫、AD(Active Directory)、Web Service及其他方式取得數據,或者將用戶數據輸入的數據保存到數據庫、AD、Web Service等中。

一、Model的任務

    Model的獨立性很高,所以VS方案中有多個要開發的項目,一般會將Model獨立成一個項目,好讓Model項目在不同的項目之間共享。

二、創建基礎數據模型

    使用MVC開發MVC項目時,不妨好好利用VS開發工具帶來的便利。尤其是開發繁瑣的Model任務時,若使用內置化開發工具,能有效提升整體開發效率。使用Entity Framwork開發數據模型的界面,通過"模型瀏覽器"窗口,可以方便地瀏覽所有數據庫與實體對象的對應,並能通過可拖拽的可視化工具開發與定義模型之間的關系。

  2.1 用LINQ to SQL自動創建數據模型

    Step01:選擇mvc項目下的"Models"文件夾,單擊鼠標右鍵,在彈出的快捷菜單中一次選取"添加"—"新建項目"選項。

    Step02:在"添加新項目"窗口中選擇"數據"模板,再選擇"LIBQ to SQL類"選項,輸入文件名稱,創建dbml文件。

    Step03:在"視圖"下拉列表中選擇"服務器資源管理器"選項,並在"服務器資源管理器"窗口中新建數據連接。選選中"數據連接"選項,單擊鼠標右鍵,在彈出的快捷慘淡中依次選擇"數據連接"—"加入數據連接"選項。

    Step04:將定義好的數據庫連接打開,並將要運用子啊MVC的數據表拖拽到DBML的設計視圖。

    Step05:VS2010會自動產生所有與SQL Server數據庫對應的實體對象。

    基本上已經創建完所有MVC需要的數據模型了。在創建完的后自動生成的類文件中,可以看到許多通過VS自動產生的類,這些文件內容是所有與數據庫表格對應的.NET類。

  2.2 用Entity Framwork自動創建數據模型

    即選中MVC項目的Models文件夾,單擊鼠標右鍵,選擇"添加"—"新建項目"選項。然后選擇"數據"模板中的ADO.NET 實體數據模型。然后按照步驟和實際表格情況選擇。(略)

    如果希望Entity Framework能正確處理默認值字段,就必須手動編輯edmx文件的xml代碼,並將這些字段逐一修正。

    Step01:在"解決方案..."選擇"Model1.edmx"文件並單擊鼠標右鍵,選擇打開方式,用不同的打開方式打開文件。

    Step02:選擇"XML(文字)編輯器"打開。

    Step03:打開后,找到SSDL程序段,並找到每一個EntityType段。

    Step04:在含有默認值的字段<Property>標簽中加上"StoreGeneratePattern="Computed""

  2.3 手動創建數據模型

    在MVC中手動創建模型,其實跟創建一般的C#類沒有什么不同,范例如下:

1     Public class MessageViewModel
2     {
3          public int TotalPage { get; set; }
4          public int TotalPage { get; set; }
5          public IEnumerable<Message> Messages { get; set; }
6     }

三、擴充基礎數據模型

TIP :雖然通過工具產生的數據模型類別還是可以手動修改,但是通常不會去修改這些內容,否則下次再通過工具修改數據模型定義時,又要重新生成程序代碼,並覆蓋我們先前自定義的部分。

  3.1 定義Model的Metadata

    Metadata用於定義數據模型的相關屬性,例如顯示名稱、數據長度及數據格式驗證等。

    System.ComponentModel.DataAnnotatis命名空間的類提供了驗證屬性,如圖:

屬性名稱

描  述

StringLength

字符串字段所允許的最大長度

Required

必填字段

RegularExpression

字段內容必須符合所指定的規則表達式

Range

數字字段必須符合的范圍

    以下建一個簡單的會員數據模型類范例。

    利用System.ComponentModel.DataAnnotatis命名空間為每個字段加上批注。每個會員都有姓名、E-mail及表情圖3個字段:姓名必填,用Required屬性;E-mail必須符合正確格式,用Regular Expression屬性驗證;表情圖需從限定的3個圖示中挑選一個,在數據庫里以int格式來進行定義。所有用Range屬性驗證只能為1~3的整數。范例代碼如下:

1    public class Member
2     {
3         [Required]
4         public string Name{get;set;}
5         [RegularExpression(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)| (([\w-]+\.)+))([a-zA-Z]{2,4})$",ErrorMessage="請輸入正確的Email格式")]
6         public string Email{get;set;}
7         [Range(1,3,ErrorMessage="請選擇代表圖示")]
8         public Int32 EmotionIcon{get;set;}
9     }

    上述定義方式不適用於LINQ to SQL環境。因為在LINQ to SQL環境所有數據模型的類都由VS自動產生。不會去手動修改生成的代碼,而是通過分類的方式來延伸這個類的輔助信息。部分類代碼:

1     namespace MvcGuestbook.Models
2     {
3          public partial class Member
4          {
5          }
6     }

    在部分類中直接寫上同名的屬性(Property)時,必須通過DataAnnotations命名空間提供的MetadataType屬性來克服這個限制,這樣才能在不分類中加上個字段的屬性(Attribute)。

TIP :由於只有方法、類、結構或接口可以被聲明為partial,因此不能再部分類中為現有的屬性(Property)應用額外屬性(attribute)。

    這種特殊寫法可以參考以下范例,要先在不分類上應用一個MetadataType屬性,並導入一個用來設定Metadata的對象類。這個Metadata的對象類可以直接在數據模型部分類里聲明,並設定為私用類(Private Class),示例如下:

    最后,完成的程序代碼如下:

View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.ComponentModel.DataAnnotations;
 6 using System.ComponentModel;
 7 
 8 namespace MvcApplication1.Models
 9 {
10      [MetadataType(typeof(MemberMetadata))]
11     public partial class Member
12     {
13         private class MemberMetadata
14         {
15             public int ID { get; set; }
16 
17             [Required(ErrorMessage = "請輸入賬號")]
18             [StringLength(50, ErrorMessage = "請勿輸入超過50個字")]
19             [DisplayName("賬號")]
20             public string Account { get; set; }
21 
22             [Required(ErrorMessage = "請輸入密碼")]
23             [StringLength(50, ErrorMessage = "請勿輸入超過50個字")]
24             [DisplayName("密碼")]
25             public string Password { get; set; }
26 
27             [Required(ErrorMessage = "請輸入昵稱")]
28             [StringLength(50, ErrorMessage = "請勿輸入超過50個字")]
29             [DisplayName("昵稱")]
30             public string NickName { get; set; }
31 
32             [Required(ErrorMessage = "請輸入中文名")]
33             [StringLength(50, ErrorMessage = "請勿輸入超過50個字")]
34             [DisplayName("中文姓名")]
35             public string CHName { get; set; }
36 
37             [Required(ErrorMessage = "請輸入Email")]
38             [StringLength(255, ErrorMessage = "請勿輸入超過255個字")]
39             [DisplayName("Email")]
40             [RegularExpression(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)| (([\w-]+\.)+))([a-zA-Z]{2,4})$", ErrorMessage = "請輸入正確的Email格式")]
41             public string Email { get; set; }
42 
43             public bool IsAdmin { get; set; }
44 
45             [Required(ErrorMessage = "請選擇代表圖標")]
46             [Range(1, 3, ErrorMessage = "輸入的值必須介於1到3之間")]
47             [DisplayName("代表圖標")]
48             public int EmotionIcon { get; set; }
49 
50             public DateTime CreateTime { get; set; }
51         }
52     }
53 }

NOTE :采用上述方法只是為了使用MetadataType屬性來擴充個字段的屬性(Attribute),而對於這些MetadataType屬性中所定義的屬性(Property),其所定義的類並不重要,重要的是這些屬性(Property)名稱要與數據模型類中定義的屬性(Property)名稱一樣—就算你將所有字段都定義成object類也沒關系。

  3.2 自定義Metadata屬性

    前面已經用RegularExpression
屬性來驗證E-mail字段,但如果有大量使用需要,程序代碼就會顯得有些復雜,可以視需要來自定義驗證屬性。以驗證E-mail屬性。以E-mail字段為例,可以繼承RegularExpressionAttribute類,並實現另一個驗證屬性,示例如下:

1    public class EmailAttribute : RegularExpressionAttribute
2     {
3         public EmailAttribute() :
4             base(@"^([\w-\.]+)@((\[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.))([a-zA-Z]{2,4})$") { }
5     }

    如此一來,就可以使用Email屬性來聲明字段的驗證規則了,示例如下:

1      [Email(ErrorMessage = "請輸入正確的Email.")]
2       public string Email { get; set; }

四、實現庫模式

    庫模式(Repository pattern)是專門用於訪問數據的一種樣式(Pattern),其設計方式很簡繁:首先定義接口(Interface),看你希望將什么樣的接口提供給訪問數據庫的類(如Controller),接着再實現該接口。接口與類(Class)的切割將有助於開發單元測試,也可讓測試驅動開發(Test Driven Development,TDD)進行得較為順利。以會員數據為例來說明如何實現庫樣式,主要有3個步驟。

    Step01:創建接口,定義可操作的方法。

    Step02:創建類,實現接口。

    Step03:在Controller中以接口來操作這個類。

    范例:會員數據

    Step01:創建ImemberRepository接口,並將其作為訪問會員數據接口,示例如下:

1     public interface IMemberRepository
2     {
3         IQueryable<Member> FindAllMembers();
4         Member GetMemberById(int id);
5         Member GetMemberByAccount(string account);
6         void Add(Member Member);
7         bool Delete(int id);
8         void Save();
9     }

    Step02:實現IMemberRepository接口,示例如下。

 1     public class MemberRepository : IMemberRepository
 2     {
 3         protected MvcApplication1.Models.GuestbookEntities db = new Models.GuestbookEntities();
 4         //protected MvcGuestBookDataContext db = new MvcGuestBookDataContext();
 5         IQueryable<Member> IMemberRepository.FindAllMembers()
 6         {
 7             return db.Member;
 8         }
 9         Member IMemberRepository.GetMemberById(int id)
10         {
11             return db.Member.Where(p => p.ID == id).FirstOrDefault();
12         }
13         Member IMemberRepository.GetMemberByAccount(string account)
14         {
15             return db.Member.Where(p => p.Account == account).FirstOrDefault();
16         }
17         void IMemberRepository.Add(Member Member)
18         {
19             db.Member.InsertOnSubmit(Member);
20         }
21         bool IMemberRepository.Delete(int id)
22         {
23             var m = db.Member.FirstOrDefault(p => p.ID == id);
24             if (m != null)
25             {
26                 db.Member.DeleteOnSubmit(m);
27                 return true;
28             }
29             else
30             {
31                 return false;
32             }
33         }
34         void IMemberRepository.Save()
35         {
36             db.SubmitChanges();
37         }
38     }

    Step03 :在Controller訪問數據時,可定義一個IMemberRepository接口類的對象,讓該Controller能使用這些對象來訪問數據,並新建Controller類的構造符,讓該Controller類可以先創建MemberRepository類的實體,程序范例如下。

 1    public class MemberController : Controller
 2     {
 3         IMemberRepository _r;
 4         public MemberController()
 5             : this(new MemberRepository())
 6         { }
 7         public MemberController(IMemberRepository r)
 8         {
 9             _r = r;
10         }
11     }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM