• 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),示例如下:

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

    复制代码
     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     }
  • 相关阅读:
    Codeforces Round #629 (Div. 3) (A ~ F)
    st表
    Educational Codeforces Round 81 (Rated for Div. 2)
    hihocoder#1996 : 01匹配
    P2056 [ZJOI2007]捉迷藏
    P2495 [SDOI2011]消耗战
    GUETOJ1335
    优先队列重载比较运算
    CCF认证201909-4 推荐系统
    P3178 [HAOI2015]树上操作
  • 原文地址:https://www.cnblogs.com/Italianetz/p/3432890.html
Copyright © 2020-2023  润新知