• 十、使用Linq to Sql创建模型层


    这篇文章中我们建造一个电影数据库管理程序,在这里我们以一种极快极简单的方式来创建电影数据库管理程序,在控制层中直接对数据库进行操作。
    接着我们学习使用Reporsitory模式,使用Repository模式需要我们额外化些力气,但它可以使我们的程序更容易测试,更好地应对变化。

    一、什么是模型类
    MVC模型层包含除了视图层和控制层之外的所有的逻辑MVC模型层包含所有的商业逻辑数据访问逻辑
    我们可以使用各种不同的技术来实现数据访问逻辑。如:我们可以使用Microsoft Entity Framework,NHibernate,Subsonic或ADO.NET类来建造。
    在这篇文章中,我们使用Linq to Sql来实现对数据库的查询和更新。Linq to Sql为我提供了操作Sql Server数据库的非常简单的接口,但不要以为ASP.NET MVC框架只能绑定Linq to Sql一起使用,ASP.NET MVC兼容于任何数据访问技术。

    二、创建电影资料数据库
    在这篇文章中,为了演示如何创建模型类,我们建立一个简单的电影数据库管理程序。
    第一步创建一个新的数据库。在解决方案文件夹中右击App_Data文件夹选择“Add”-“New Item”,在弹出的对话框中,选择Sql Server Database,命名为MoviesDB.mdf。点击Add按钮,如图所示


    《图1》
    当我们创建新数据库后,我们在App_Data文件夹中双击MoviesDB.mdf文件,打开SqlServer Explorer如下图所示


    《图2》
    现在我们向数据库中添加表以保存电影信息。在SqlServer Explorer中右击Tables文件夹,选择“Add”-“New Table”,打开数据库设计界面,如图所示


    《图3》
    我们需要对Id列做两件事,首选需要把Id列标记为主键列,Linq to Sql在对数据进行insert和update操作时需要指定主键列信息,其次需要把Id列标记为自增长列。

    三、创建Linq to Sql类
    我们本程序的的MVC模型层中包含对tblMovie数据库的Linq to Sql类。创建Linq to Sql 类的简单方法是:右击Models文件夹,选择“Add”-“New Item”,在弹出的对话框中选择Linq to Sql Classes,并将其命名为Move.dbml,点击“Add”按钮。


    《图4》
    创建完Linq to Sql类后,会显示Object Relational Designer。我们从Server Explorer窗口中拖动表到Object Relation Designer上,这时会在设计器上现示数据表。


    《图5》
    默认情况下,当我们拖一个表到Object Relation Designer上的时候,Object Relation Designer会创建一个对应的类。如果我们不想让我们的类名与表同名(tblMovie),在设计器中点击类名把它改成你想要的即可。
    最后记得点击保存按钮,以生成并保存我们的Linq to Sql类,否则Object Relation Designer不会生成Linq to Sql类。

    四、在控制器动作中使用Linq to Sql
    现在我们有了Linq to Sql类,我们可以使用这些类从数据库检索数据。在这一节中我们学习:如何在控器动作中使用Linq to Sql类直接访问数据库,并在视图层显示tblMovies表的信息。
    首先,我们修改HomeController类,这可以在应用程序Controllers文件夹中找到。把类的代码改成如下形式:
    Listing 1 – Controllers\HomeController.cs
    using System.Linq;
    using System.Web.Mvc;
    using MvcApplication1.Models;
    namespace MvcApplication1.Controllers
    {     
    [HandleError]     
    public class HomeController : Controller     
    {          
       public ActionResult Index()          
       {               
        var dataContext = new MovieDataContext();               
        var movies = from m in dataContext.Movies select m;               
        return View(movies);
              
       }     
    }
    }

    在上面的代码的Index()动作中,我们使用Linq to Sql的DataContext(MovieDataContext类)操作MovieDB数据库。MovieDataContext类是由Object Relation 设计器自动生成的类。
    Linq查询是使用DataContext检索tblMovies表中所有数据。电影列表数据被赋给局部变量movies,最后movies列表通过viewdata传输给视图层。
    要显示所有的电影信息,我们需要修改应用程序Views/Home/Index视图。代码如下:
    Listing 2 – Views\Home\Index.aspx
    <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
    <%@ Import Namespace="MvcApplication1.Models" %>
    <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">     
    <ul>          
    <% foreach (Movie m in (IEnumerable)ViewData.Model)          
       { %>               
       <li> <%= m.Title %> </li>          
       <% } %>
         
    </ul>
    </asp:Content>
    上面的代码中包含<%@ Import Namespace="MvcApplication1.Models" %>,它导入MvcApplication1.Models命名空间,MvcApplication1.Models是我们模型类所在的命名空间。
    上面的代码有一个foreach循环迭代ViewData.Model中的每一项,每一部电影的标题就显示出来了。
    我们可以看到,在上面的代码中,我们把ViewData.Model强制转换为 IEnumerable类型。只有这样我们才能对ViewData.Model返回的数据进行迭代。
    如果我们现在运行程序会发现是个空白页面,因为我们还没有向数据库添加数据,在Server Explorer窗口中右击tblMovies表,在弹出菜单中选择“Show Table Data”,然后输入如图的数据。


    《图6》
    当我们向数据库的表中添加完记录后,再运行程序的时候,我们会发现所有的电影数据都显示在列表中。如图所示。


    《图7》

    五、使用Repository模式
    在前面部分中,我们在控制器动作中直接使用Linq to Sql类。在简单的应用程序中我们这种做法并没有什么问题 ,但对于复杂的程序,这种直接在控制器中写Linq to Sql操作数据库的做法会给我们带来不少的麻烦。
    在控制器中直接编写Linq to Sql的这种做法,在将来我们变更数据库访问技术的时候会变得很困难比如说,我们将来可以会使用Microsoft Entity Framework来替换Microsoft Linq to Sql来访问数据库,一旦这样做,那我们需要去修改每个控制器的代码。
    另外在控制器中直接编写Linq to Sql代码会使我们很难为应用程序编写单元测试。一般地,当我们进行单元测试的时候,并不需要直接与数据库交互,因为我们想要测试的是我们的程序逻辑,而不是测试数据库服务器。
    为了使MVC应用程序更易维护,更易测试,我们应考虑使用Repository模式。
    我们创建一个接口,该接口中定义了对数据库操作所必需的方法声明。然后我们编写类,在类中实现接口中的方法,采取某种数据库访问技术操作数据库。在控制器中,我们基于接口编写代码,这样我们就可以在将来变更数据库访问技术,而不需要修改控制器了。
    这里我们编写了一个接口IMovieRepository,该接口中定义了一个方法ListAll();
    Listing 3 – Models\IMovieRepository.cs
    using System.Collections.Generic;
    namespace MvcApplication1.Models
    {     
    public interface IMovieRepository     
    {          
       IList<Movie> ListAll();     
    }
    }
    然后编写一个类MovieRepository实现IMovieRepository接口,在该类中实现方法ListAll()。
    Listing 4 – Models\MovieRepository.cs
    using System.Collections.Generic;
    using System.Linq;
    namespace MvcApplication1.Models
    {     
    public class MovieRepository : IMovieRepository     
    {          
       private MovieDataContext _dataContext;          
       public MovieRepository()          
       {                
        _dataContext = new MovieDataContext();          
       }          
       #region IMovieRepository Members          
       public IList<Movie> ListAll()          
       {               
        var movies = from m in _dataContext.Movies select m;               
        return movies.ToList();          
       }          
       #endregion     
    }
    }

    最后,我们在控制器MoviesController中使用Repository 模式,而不是直接使用Linq to Sql类操作数据库。
    Listing 5 – Controllers\MoviesController.cs
    using System.Web.Mvc;
    using MvcApplication1.Models;
    namespace MvcApplication1.Controllers
    {     
    public class MoviesController : Controller     
    {          
       private IMovieRepository _repository;          
       public MoviesController() : this(new MovieRepository())          
       {          
       }          
       public MoviesController(IMovieRepository repository)          
       {               
        _repository = repository;          
       }         
       public ActionResult Index()          
       {               
        return View(_repository.ListAll());          
       }     
    }
    }
    上面的代码中,MoviesController类有两个构造函数,第一个构造函数是个无参构造函数。该构造函数被调用的时候,创建一个MovieRepository类的实例,并把这个实例传递给第二个构造函数。
    第二个构造函数有一个IMovieRepository型的构造参数。这个构造函数就是把传进来的参数赋给成员变量_repository。
    MoviesController控制器的这种做法是为了实现依赖注入模式而设计的,即我们经常说的“构造依赖注入”。关于依赖注入的相关内空请参见Martin Fowler的文章
    http://martinfowler.com/articles/injection.html

    还需要引起我们注意的是,在 MoviesController类中,我们是与IMovieRepository接口进行交互,而不是直接与MovieRepository类进行交互。这就是我们常说的“要依赖于抽象,而不依赖于具体。”

    当我们想修改数据库访问代码的时候,我们只需要编写另一个类,该类也实现IMovieRepository接口。假设,我们创建了EntityFrameworkMovieRepository类或SubSonicMovieRepository类,因为我们控制器是基于接口编码的,所以我们在构造控制器的时候传入其中上面两个类的一个实例,那控制器和相关的类就要以配合工作了。

    如果我们想对MoviesController类进行测试的话,我们可以传一个fake类到MoviesController控制器。这个fake类也是实现IMovieRepository接口,但并没有真正访问数据库。这样我们就可以只对MoviesController类进行测试,而没必要使用真实的数据访问逻辑。

    总结
    这篇文章演示了如何使用Linq to Sql创建MVC模型类。
    首先,我们需要创建Linq to Sql类,然后直接在控制器动作中使用这些类。这种做法可以使我们快速简单地在MVC应用程序中显示数据库中的数据。
    然后,我们又把问题稍微复杂化了一些,但数据显示更灵活,程序的弹性更大。这是因为我们使用了Repository模式。这种模式把所有的数据库访问逻辑全放在一个模型类中。在控制器中我们只对接口进行编程,这更能够为我们将来更改数据访问方式带来很大的方便 ,并使程序更易测试。

  • 相关阅读:
    ShoneSharp语言(S#)的设计和使用介绍系列(10)— 富家子弟“语句“不炫富
    ShoneSharp语言(S#)的设计和使用介绍系列(9)— 一等公民“函数“爱炫巧
    ShoneSharp语言(S#)的设计和使用介绍系列(8)— 最炫“公式”风
    ShoneSharp语言(S#)的设计和使用介绍系列(1)— 开篇
    ShoneSharp语言(S#)软件更新13.7版
    ShoneSharp语言(S#)软件更新13.6版
    ShoneSharp语言(S#)的设计和使用介绍系列(7)— 布尔Bool及对象Object
    ShoneSharp语言(S#)的设计和使用介绍系列(6)— 字符串String
    自然语言处理系列-4条件随机场(CRF)及其tensorflow实现
    【NLP】老司机带你入门自然语言处理
  • 原文地址:https://www.cnblogs.com/zxktxj/p/2461534.html
Copyright © 2020-2023  润新知