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

2020-12-13 15:35

阅读:515

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

1.Web项目

1.1概述

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

1.2创建项目

soscw.com,搜素材

1.3添加实体类

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

soscw.com,搜素材soscw.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类,其代码:

soscw.com,搜素材soscw.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文件夹上右键,添加-》控制器:

soscw.com,搜素材

选择模板后,点添加:

soscw.com,搜素材

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

soscw.com,搜素材

然后勾选异步:

soscw.com,搜素材

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

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

soscw.com,搜素材

1.4启用迁移

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

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

启用迁移命令:

soscw.com,搜素材

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

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

1.5添加迁移

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

soscw.com,搜素材soscw.com,搜素材
using System.Data.Entity.Migrations;
using WebApi05.Models;

namespace WebApi05.Migrations
{
    internal sealed class Configuration : DbMigrationsConfiguration
    {
        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

添加迁移命令:
soscw.com,搜素材

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

1.6更新数据库

输入命令:

soscw.com,搜素材

1.7查看数据库

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

soscw.com,搜素材

1.8配置迁移

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

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

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

soscw.com,搜素材soscw.com,搜素材
    "WebApi05.Models.EFContext,WebApi05" >
        
        "WebApi05.Models.InitData,WebApi05" />
      
View Code

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

soscw.com,搜素材soscw.com,搜素材
using System.Data.Entity;
using System.Data.Entity.Migrations;

namespace WebApi05.Models
{
    public class InitData : DropCreateDatabaseIfModelChanges
    {
        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

soscw.com,搜素材soscw.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 Authors { get; set; }
      public  DbSet Books { get; set; }
    }
}
View Code

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

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

soscw.com,搜素材

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

soscw.com,搜素材soscw.com,搜素材
        // GET: api/Books
        public IQueryable GetBooks()
        {
            return db.Books.Include(b => b.Author);
        }
View Code

再一次运行:

soscw.com,搜素材

再看VS输出窗户:

soscw.com,搜素材

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

1.10数据传输DTO

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

soscw.com,搜素材soscw.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,其代码:

soscw.com,搜素材soscw.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):

soscw.com,搜素材soscw.com,搜素材
        // GET api/Books
        public IQueryable 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 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

再一次运行:
soscw.com,搜素材

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

soscw.com,搜素材

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

soscw.com,搜素材soscw.com,搜素材
        [ResponseType(typeof(Book))]
        public async Task 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):

soscw.com,搜素材

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

soscw.com,搜素材soscw.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 ()中:

soscw.com,搜素材soscw.com,搜素材
            bundles.Add(new ScriptBundle("~/bundles/app").Include(
              "~/Scripts/knockout-{version}.js",
              "~/Scripts/app.js"));
View Code

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

soscw.com,搜素材soscw.com,搜素材
@section scripts {
    @Scripts.Render("~/bundles/app")
}

class="page-header">

书籍展示

class="row">
class="col-md-4">
class="panel panel-default">
class="panel-heading">

class="panel-title">书籍列表

class="panel-body">
    class="list-unstyled" data-bind="foreach: books">
  • "text: AuthorName">: "text: Title"> "#">详细
class="alert alert-danger" data-bind="visible: error">

"text: error">

class="col-md-4">
class="col-md-4">
View Code

运行网站:
soscw.com,搜素材

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

1.14显示详细页

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

soscw.com,搜素材soscw.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,修改为:

soscw.com,搜素材soscw.com,搜素材
@section scripts {
    @Scripts.Render("~/bundles/app")
}
class="page-header">

书籍展示

class="row">
class="col-md-4">
class="panel panel-default">
class="panel-heading">

class="panel-title">书籍列表

class="panel-body">
class="alert alert-danger" data-bind="visible: error">

"text: error">

class="col-md-4">
class="panel panel-default">
class="panel-heading">

class="panel-title">详细

class="table">
Author "text: detail().AuthorName">
Title "text: detail().Title">
Year "text: detail().Year">
Genre "text: detail().Genre">
Price "text: detail().Price">
class="col-md-4">
View Code

运行网站:

soscw.com,搜素材

1.15添加一个

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

soscw.com,搜素材soscw.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,修改为:

soscw.com,搜素材soscw.com,搜素材
@section scripts {
    @Scripts.Render("~/bundles/app")
}
class="page-header">

书籍展示

class="row">
class="col-md-4">
class="panel panel-default">
class="panel-heading">

class="panel-title">书籍列表

class="panel-body">
class="alert alert-danger" data-bind="visible: error">

"text: error">

class="col-md-4">
class="panel panel-default">
class="panel-heading">

class="panel-title">详细

class="table">
Author "text: detail().AuthorName">
Title "text: detail().Title">
Year "text: detail().Year">
Genre "text: detail().Genre">
Price "text: detail().Price">
class="col-md-4">
class="panel panel-default">
class="panel-heading">

class="panel-title">Add Book

class="panel-body">
class="form-horizontal" data-bind="submit: addBook">
class="form-group">
class="col-sm-10"> select data-bind="options:authors, optionsText: ‘Name‘, value: newBook.Author">select>
class="form-group" data-bind="with: newBook">
class="col-sm-10"> "text" class="form-control" id="inputTitle" data-bind="value:Title" />
class="col-sm-10"> "number" class="form-control" id="inputYear" data-bind="value:Year" />
class="col-sm-10"> "text" class="form-control" id="inputGenre" data-bind="value:Genre" />
class="col-sm-10"> "number" step="any" class="form-control" id="inputPrice" data-bind="value:Price" />
View Code

网站运行:

soscw.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


评论


亲,登录后才可以留言!