码迷,mamicode.com
首页 > Windows程序 > 详细

WebApi学习笔记05:使用webapi模板--实体类--EF--迁移--Knockout

时间:2014-11-05 14:33:56      阅读:1079      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   color   ar   os   使用   for   

1.Web项目

1.1概述

本例主要介绍EF,数据初始化迁移,Knockout.js使用……

1.2创建项目

bubuko.com,布布扣

1.3添加实体类

在Models文件夹下,先添加一个Author.cs类,其代码:

bubuko.com,布布扣
using System.ComponentModel.DataAnnotations;

namespace WebApi05.Models
{
    public class Author
    {
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
    }
}
View Code

 在Models文件夹下,再添加一个Book.cs类,其代码:

bubuko.com,布布扣
using System.ComponentModel.DataAnnotations;

namespace WebApi05.Models
{
    public class Book
    {
        public int Id { get; set; }
        [Required]
        public string Title { get; set; }
        public int Year { get; set; }
        public decimal Price { get; set; }
        public string Genre { get; set; }

        // 外键
        public int AuthorId { get; set; }
        // 导航属性
        public Author Author { get; set; }
    }
}
View Code

1.4添加控制器

这次我们使用基架模板来创建控制器。如果需要模型类和上下文类刚新建的,需要先生成一下项目,才能使得基架识得其类。

在Controllers文件夹上右键,添加-》控制器:

bubuko.com,布布扣

选择模板后,点添加:

bubuko.com,布布扣

这里先点“数据上下文类”后的+号,来新建数据库上下文设置:

bubuko.com,布布扣

然后勾选异步:

bubuko.com,布布扣

这样基架自动为项目添加了Controllers\AuthorsController.cs和Models\EFContext.cs两个类,并在Web.config中添加数据库连接字符串。

由于生成的EFContext.cs是新建的,我们又需要先生成项目。再来创建Book控制器。创建步骤和前面一样:

bubuko.com,布布扣

1.4启用迁移

vs里,工具-》NuGet程序包管理器-》程序包管理器控制器台:

输入命令:get-help migration 来查看帮助。

启用迁移命令:

bubuko.com,布布扣

注意:选择默认项目,也就是在那个项目进行迁移。

命令执行后,在根目录下生成一个Migrations文件夹,里面有一个Configuration.cs类。

1.5添加迁移

先设置初始化数据,把Migrations\Configuration.cs代码修改为:

bubuko.com,布布扣
using System.Data.Entity.Migrations;
using WebApi05.Models;

namespace WebApi05.Migrations
{
    internal sealed class Configuration : DbMigrationsConfiguration<EFContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(EFContext context)
        {
            context.Authors.AddOrUpdate(x => x.Id,
                  new Author() { Id = 1, Name = "Jane Austen" },
                  new Author() { Id = 2, Name = "Charles Dickens" },
                  new Author() { Id = 3, Name = "Miguel de Cervantes" });

            context.Books.AddOrUpdate(x => x.Id,
                  new Book()
                  {
                      Id = 1,
                      Title = "Pride and Prejudice",
                      Year = 1813,
                      AuthorId = 1,
                      Price = 9.99M,
                      Genre = "Comedy of manners"
                  },
                  new Book()
                 {
                     Id = 2,
                     Title = "Northanger Abbey",
                     Year = 1817,
                     AuthorId = 1,
                     Price = 12.95M,
                     Genre = "Gothic parody"
                 },
                  new Book()
                 {
                     Id = 3,
                     Title = "David Copperfield",
                     Year = 1850,
                     AuthorId = 2,
                     Price = 15,
                     Genre = "Bildungsroman"
                 },
                  new Book()
                  {
                      Id = 4,
                      Title = "Don Quixote",
                      Year = 1617,
                      AuthorId = 3,
                      Price = 8.95M,
                      Genre = "Picaresque"
                  });
        }
    }
}
View Code

添加迁移命令:
bubuko.com,布布扣

执行成功后,这是Migrations文件夹下会多出一个:时间戳+FirstInitData.cs类。

1.6更新数据库

输入命令:

bubuko.com,布布扣

1.7查看数据库

我们看迁移数据库是否OK。VS里,视图-》服务器资源管理器:

bubuko.com,布布扣

1.8配置迁移

通过迁移“三步走”(启用,添加,更新),我们可以手动来迁移数据库。但有时根据需要是否进行迁移初始化数据,

能不能通过配置文件了来决定(也可以在程序入口写代码执行方法,但这样改动后需要重新编译项目)。

打开Web.config,在 <entityFramework>节点下,添加下面代码:

bubuko.com,布布扣
    <contexts>
      <!--上下文类命名空间,项目程序集名称-->
      <!--<context type="WebApi05.Models.EFContext,WebApi05" disableDatabaseInitialization="false">-->
      <context type="WebApi05.Models.EFContext,WebApi05" >
        <!--初始数据命名空间,项目程序集名称-->
        <databaseInitializer type="WebApi05.Models.InitData,WebApi05" />
      </context>
    </contexts>
View Code

在Models文件夹下,添加InitData.cs类,其代码:

bubuko.com,布布扣
using System.Data.Entity;
using System.Data.Entity.Migrations;

namespace WebApi05.Models
{
    public class InitData : DropCreateDatabaseIfModelChanges<EFContext>
    {
        protected override void Seed(EFContext context)
        {
            context.Authors.AddOrUpdate(x => x.Id,
                  new Author() { Id = 1, Name = "Jane Austen" },
                  new Author() { Id = 2, Name = "Charles Dickens" },
                  new Author() { Id = 3, Name = "Miguel de Cervantes" });

            context.Books.AddOrUpdate(x => x.Id,
                  new Book()
                  {
                      Id = 1,
                      Title = "Pride and Prejudice",
                      Year = 1813,
                      AuthorId = 1,
                      Price = 9.99M,
                      Genre = "Comedy of manners"
                  },
                  new Book()
                  {
                      Id = 2,
                      Title = "Northanger Abbey",
                      Year = 1817,
                      AuthorId = 1,
                      Price = 12.95M,
                      Genre = "Gothic parody"
                  },
                  new Book()
                  {
                      Id = 3,
                      Title = "David Copperfield",
                      Year = 1850,
                      AuthorId = 2,
                      Price = 15,
                      Genre = "Bildungsroman"
                  },
                  new Book()
                  {
                      Id = 4,
                      Title = "Don Quixote",
                      Year = 1617,
                      AuthorId = 3,
                      Price = 8.95M,
                      Genre = "Picaresque"
                  });
        }
    }
}
View Code

测试:删除原来数据或更改连接字符串中数据库名称。这样程序运行涉及到数据库访问时,就可以自动迁移了。

1.9查看生成SQL语句

修改Models\EFContext.cs

bubuko.com,布布扣
using System.Data.Entity;
using System.Diagnostics;

namespace WebApi05.Models
{
    public class EFContext : DbContext
    {

        public EFContext()
            : base("name=EFContext")
        {
            this.Database.Log = s => Debug.WriteLine(s);
        }

      public  DbSet<Author> Authors { get; set; }
      public  DbSet<Book> Books { get; set; }
    }
}
View Code

打开vs里,视图-》输出(窗户),运行网站地址http://localhost:8935/api/books  这时输出窗户可以看到生成的SQL语句:
bubuko.com,布布扣

查询结果是(可以使用fiddler工具看JSON格式):

bubuko.com,布布扣

可以看到Author数据(模型导航属性)没有加载。修改Controllers\BooksController.cs中的GetBooks(),如下:

bubuko.com,布布扣
        // GET: api/Books
        public IQueryable<Book> GetBooks()
        {
            return db.Books.Include(b => b.Author);
        }
View Code

再一次运行:

bubuko.com,布布扣

再看VS输出窗户:

bubuko.com,布布扣

如果在模型导航属性加入virtual关键字,这是查询为延迟加载(也就是多次访问数据库查询),这里就不演示。(在专门EF系列中再介绍)

1.10数据传输DTO

 在Models文件夹下,创建BookDTO.cs,其代码:

bubuko.com,布布扣
namespace WebApi05.Models
{
    public class BookDTO
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string AuthorName { get; set; }
    }
}
View Code

在Models文件夹下,创建BookDetailDTO.cs,其代码:

bubuko.com,布布扣
namespace WebApi05.Models
{
    public class BookDetailDTO
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public int Year { get; set; }
        public decimal Price { get; set; }
        public string AuthorName { get; set; }
        public string Genre { get; set; }
    }
}
View Code

1.11修改控制器
打开Controllers\BooksController.cs,修改GetBooks()和GetBook(int id):

bubuko.com,布布扣
        // GET api/Books
        public IQueryable<BookDTO> GetBooks()
        {
            var books = from b in db.Books
                        select new BookDTO()
                        {
                            Id = b.Id,
                            Title = b.Title,
                            AuthorName = b.Author.Name
                        };
            return books;
        }
        // GET api/Books/5
        [ResponseType(typeof(BookDetailDTO))]
        public async Task<IHttpActionResult> GetBook(int id)
        {
            var book = await db.Books.Include(b => b.Author).Select(b =>
                new BookDetailDTO()
                {
                    Id = b.Id,
                    Title = b.Title,
                    Year = b.Year,
                    Price = b.Price,
                    AuthorName = b.Author.Name,
                    Genre = b.Genre
                }).SingleOrDefaultAsync(b => b.Id == id);
            if (book == null)
            {
                return NotFound();
            }

            return Ok(book);
        } 
View Code

再一次运行:
bubuko.com,布布扣

再看vs输出生成SQL语句(简洁):

bubuko.com,布布扣

打开Controllers\BooksController.cs,修改PostBook(Book book):

bubuko.com,布布扣
        [ResponseType(typeof(Book))]
        public async Task<IHttpActionResult> PostBook(Book book)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            db.Books.Add(book);
            await db.SaveChangesAsync();

            db.Entry(book).Reference(x => x.Author).Load();

            var dto = new BookDTO()
            {
                Id = book.Id,
                Title = book.Title,
                AuthorName = book.Author.Name
            };

            return CreatedAtRoute("DefaultApi", new { id = book.Id }, dto);
        }
View Code

1.12Knockoutjs

安装knockoutjs(简称KO):

bubuko.com,布布扣

在Scripts文件夹下,添加app.js,其代码:

bubuko.com,布布扣
var ViewModel = function () {
    var self = this;
    self.books = ko.observableArray();//保存书籍的列表
    self.error = ko.observable();//包含一条错误消息,如果 AJAX 调用失败

    var booksUri = /api/books/;

    //AJAX助手方法
    function ajaxHelper(uri, method, data) {
        self.error(‘‘); // Clear error message
        return $.ajax({
            type: method,
            url: uri,
            dataType: json,
            contentType: application/json,
            data: data ? JSON.stringify(data) : null
        }).fail(function (jqXHR, textStatus, errorThrown) {
            self.error(errorThrown);
        });
    }

    //获取所有书籍方法
    function getAllBooks() {
        ajaxHelper(booksUri, GET).done(function (data) {
            self.books(data);
        });
    }

    //获取初始数据
    getAllBooks();
};

ko.applyBindings(new ViewModel());
View Code

打开 App_Start/BundleConfig.cs。将下面的代码添加到 RegisterBundles ()中:

bubuko.com,布布扣
            bundles.Add(new ScriptBundle("~/bundles/app").Include(
              "~/Scripts/knockout-{version}.js",
              "~/Scripts/app.js"));
View Code

1.13修改视图
把Views\Home\Index.cshtml,修改为:

bubuko.com,布布扣
@section scripts {
    @Scripts.Render("~/bundles/app")
}

<div class="page-header">
    <h1>书籍展示</h1>
</div>

<div class="row">

    <div class="col-md-4">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">书籍列表</h2>
            </div>
            <div class="panel-body">
                <ul class="list-unstyled" data-bind="foreach: books">
                    <li>
                        <strong><span data-bind="text: AuthorName"></span></strong>: <span data-bind="text: Title"></span>
                        <small><a href="#">详细</a></small>
                    </li>
                </ul>
            </div>
        </div>
        <div class="alert alert-danger" data-bind="visible: error"><p data-bind="text: error"></p></div>
    </div>

    <div class="col-md-4">
        <!-- TODO: Book details -->
    </div>

    <div class="col-md-4">
        <!-- TODO: Add new book -->
    </div>
</div>
View Code

运行网站:
bubuko.com,布布扣

注:上面详细页,并没有“激活”。

1.14显示详细页

修改Scripts\app.js,其代码为:

bubuko.com,布布扣
var ViewModel = function () {
    var self = this;
    self.books = ko.observableArray();//保存书籍的列表
    self.error = ko.observable();//包含一条错误消息,如果 AJAX 调用失败
    self.detail = ko.observable();//保存书籍详细

    var booksUri = /api/books/;

    //AJAX助手方法
    function ajaxHelper(uri, method, data) {
        self.error(‘‘); // Clear error message
        return $.ajax({
            type: method,
            url: uri,
            dataType: json,
            contentType: application/json,
            data: data ? JSON.stringify(data) : null
        }).fail(function (jqXHR, textStatus, errorThrown) {
            self.error(errorThrown);
        });
    }

    //获取所有书籍方法
    function getAllBooks() {
        ajaxHelper(booksUri, GET).done(function (data) {
            self.books(data);
        });
    }

    //获取书籍详细方法
    self.getBookDetail = function (item) {
        ajaxHelper(booksUri + item.Id, GET).done(function (data) {
            self.detail(data);
        });
    }

    //获取初始数据
    getAllBooks();
};

ko.applyBindings(new ViewModel());
View Code

继续把Views\Home\Index.cshtml,修改为:

bubuko.com,布布扣
@section scripts {
    @Scripts.Render("~/bundles/app")
}
<div class="page-header">
    <h1>书籍展示</h1>
</div>
<div class="row">

    <div class="col-md-4">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">书籍列表</h2>
            </div>
            <div class="panel-body">
                <ul class="list-unstyled" data-bind="foreach: books">
                    <li>
                        <strong><span data-bind="text: AuthorName"></span></strong>: <span data-bind="text: Title"></span>
                        <small><a href="#" data-bind="click: $parent.getBookDetail">详细</a></small>
                    </li>
                </ul>
            </div>
        </div>
        <div class="alert alert-danger" data-bind="visible: error"><p data-bind="text: error"></p></div>
    </div>

    <!-- ko if:detail() -->
    <div class="col-md-4">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">详细</h2>
            </div>
            <table class="table">
                <tr><td>Author</td><td data-bind="text: detail().AuthorName"></td></tr>
                <tr><td>Title</td><td data-bind="text: detail().Title"></td></tr>
                <tr><td>Year</td><td data-bind="text: detail().Year"></td></tr>
                <tr><td>Genre</td><td data-bind="text: detail().Genre"></td></tr>
                <tr><td>Price</td><td data-bind="text: detail().Price"></td></tr>
            </table>
        </div>
    </div>
    <!-- /ko -->

    <div class="col-md-4">
        <!-- TODO: Add new book -->
    </div>
</div>
View Code

运行网站:

bubuko.com,布布扣

1.15添加一个

修改Scripts\app.js,其代码为:

bubuko.com,布布扣
var ViewModel = function () {
    var self = this;
    self.books = ko.observableArray();//保存书籍的列表
    self.error = ko.observable();//包含一条错误消息,如果 AJAX 调用失败
    self.detail = ko.observable();//保存书籍详细
    self.authors = ko.observableArray();
    self.newBook = {
        Author: ko.observable(),
        Genre: ko.observable(),
        Price: ko.observable(),
        Title: ko.observable(),
        Year: ko.observable()
    }

    var authorsUri = /api/authors/;

    //获取所有作者
    function getAuthors() {
        ajaxHelper(authorsUri, GET).done(function (data) {
            self.authors(data);
        });
    }

    //添加书籍
    self.addBook = function (formElement) {
        var book = {
            AuthorId: self.newBook.Author().Id,
            Genre: self.newBook.Genre(),
            Price: self.newBook.Price(),
            Title: self.newBook.Title(),
            Year: self.newBook.Year()
        };

        ajaxHelper(booksUri, POST, book).done(function (item) {
            self.books.push(item);
        });
    }

    var booksUri = /api/books/;

    //AJAX助手方法
    function ajaxHelper(uri, method, data) {
        self.error(‘‘); // Clear error message
        return $.ajax({
            type: method,
            url: uri,
            dataType: json,
            contentType: application/json,
            data: data ? JSON.stringify(data) : null
        }).fail(function (jqXHR, textStatus, errorThrown) {
            self.error(errorThrown);
        });
    }

    //获取所有书籍方法
    function getAllBooks() {
        ajaxHelper(booksUri, GET).done(function (data) {
            self.books(data);
        });
    }

    //获取书籍详细方法
    self.getBookDetail = function (item) {
        ajaxHelper(booksUri + item.Id, GET).done(function (data) {
            self.detail(data);
        });
    }

    //获取初始数据
    getAllBooks();
    getAuthors();
};

ko.applyBindings(new ViewModel());
View Code

把Views\Home\Index.cshtml,修改为:

bubuko.com,布布扣
@section scripts {
    @Scripts.Render("~/bundles/app")
}
<div class="page-header">
    <h1>书籍展示</h1>
</div>
<div class="row">

    <div class="col-md-4">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">书籍列表</h2>
            </div>
            <div class="panel-body">
                <ul class="list-unstyled" data-bind="foreach: books">
                    <li>
                        <strong><span data-bind="text: AuthorName"></span></strong>: <span data-bind="text: Title"></span>
                        <small><a href="#" data-bind="click: $parent.getBookDetail">详细</a></small>
                    </li>
                </ul>
            </div>
        </div>
        <div class="alert alert-danger" data-bind="visible: error"><p data-bind="text: error"></p></div>
    </div>

    <!-- ko if:detail() -->
    <div class="col-md-4">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">详细</h2>
            </div>
            <table class="table">
                <tr><td>Author</td><td data-bind="text: detail().AuthorName"></td></tr>
                <tr><td>Title</td><td data-bind="text: detail().Title"></td></tr>
                <tr><td>Year</td><td data-bind="text: detail().Year"></td></tr>
                <tr><td>Genre</td><td data-bind="text: detail().Genre"></td></tr>
                <tr><td>Price</td><td data-bind="text: detail().Price"></td></tr>
            </table>
        </div>
    </div>
    <!-- /ko -->

    <div class="col-md-4">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Add Book</h2>
            </div>

            <div class="panel-body">
                <form class="form-horizontal" data-bind="submit: addBook">
                    <div class="form-group">
                        <label for="inputAuthor" class="col-sm-2 control-label">Author</label>
                        <div class="col-sm-10">
                            <select data-bind="options:authors, optionsText: ‘Name‘, value: newBook.Author"></select>
                        </div>
                    </div>

                    <div class="form-group" data-bind="with: newBook">
                        <label for="inputTitle" class="col-sm-2 control-label">Title</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="inputTitle" data-bind="value:Title" />
                        </div>

                        <label for="inputYear" class="col-sm-2 control-label">Year</label>
                        <div class="col-sm-10">
                            <input type="number" class="form-control" id="inputYear" data-bind="value:Year" />
                        </div>

                        <label for="inputGenre" class="col-sm-2 control-label">Genre</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="inputGenre" data-bind="value:Genre" />
                        </div>

                        <label for="inputPrice" class="col-sm-2 control-label">Price</label>
                        <div class="col-sm-10">
                            <input type="number" step="any" class="form-control" id="inputPrice" data-bind="value:Price" />
                        </div>
                    </div>
                    <button type="submit" class="btn btn-default">Submit</button>
                </form>
            </div>
        </div>
    </div>
</div>
View Code

网站运行:

bubuko.com,布布扣

2.小结

本例重点掌握EF,数据迁移,使用DTO,Knockout绑定模型输出DOM上。

随着学习深度,是不是越来越接近高大上感觉了。到目前为止,还是皮毛哦。

 

WebApi学习笔记05:使用webapi模板--实体类--EF--迁移--Knockout

标签:style   blog   http   io   color   ar   os   使用   for   

原文地址:http://www.cnblogs.com/elder/p/4075412.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!