专栏首页漫漫全栈路ANCWEB - 基于 ASP.NET CORE 2.0 的 WEB 开发 二

ANCWEB - 基于 ASP.NET CORE 2.0 的 WEB 开发 二

上一篇成功在MSSQL中创建了数据库,本篇继续。

数据库相关

为领域模型(Domain Model)添加约束

在项目中新建一个test.sql 文件,查询数据库信息。

-- 查询数据库
Select Name FROM tvdb..SysObjects Where XType='U' orDER BY Name 

-- 查询表信息
select * from information_schema.columns where table_name = 'TvNetworks';
select * from information_schema.columns where table_name = 'TvShows';

查询结果如下:

这个结果和所需要的数据库结构有一定的差异,那么,可以通过为Domain Model的相应属性添加一些约束,来进行变更。

修改之前创建的两个 Model 类,为其添加约束。

注意: 这里使用了DataAnnotation来建立约束,需要引用相关的类库。EF 约束等内容后续写篇文章专门说一下。

然后添加migrations 并执行数据库更新

dotnet ef migrations add AddConstraints
dotnet ef database update

编辑migrations添加种子数据

前面的操作,我们都是对Model 类进行修改,然后通过 EF 的migrations 的指令来对进行数据库进行操作。虽然生成了 migrations 文件,但都没有进行过了解,下面通过修改 migrations 文件来对数据库进行操作。

命令行添加一个空的migration:

dotnet ef migrations add SeedData

编辑创建的 migration 文件,参考如下:

using Microsoft.EntityFrameworkCore.Migrations;

namespace ANCWEB.Migrations
{
    public partial class SeedData : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.Sql("INSERT INTO TvNetworks (Name) VALUES ('Netflix')");
            migrationBuilder.Sql("INSERT INTO TvNetworks (Name) VALUES ('HBO')");
            migrationBuilder.Sql("INSERT INTO TvNetworks (Name) VALUES ('CBS')");
            migrationBuilder.Sql("INSERT INTO TvNetworks (Name) VALUES ('NBC')");

            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('House of Cards', (SELECT Id FROM TvNetworks WHERE Name='Netflix'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Altered Carbon', (SELECT Id FROM TvNetworks WHERE Name='Netflix'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Marvel''s Daredevil', (SELECT Id FROM TvNetworks WHERE Name='Netflix'))");

            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Game of Thrones', (SELECT Id FROM TvNetworks WHERE Name='HBO'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Silicon Valley', (SELECT Id FROM TvNetworks WHERE Name='HBO'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Veep', (SELECT Id FROM TvNetworks WHERE Name='HBO'))");

            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('NCIS', (SELECT Id FROM TvNetworks WHERE Name='CBS'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('The Big Bang Theory', (SELECT Id FROM TvNetworks WHERE Name='CBS'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Criminal Minds', (SELECT Id FROM TvNetworks WHERE Name='CBS'))");

            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Friends', (SELECT Id FROM TvNetworks WHERE Name='NBC'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Chicago Fire', (SELECT Id FROM TvNetworks WHERE Name='NBC'))");
            migrationBuilder.Sql("INSERT INTO TvShows (Name, TvNetworkId) VALUES ('Will & Grace', (SELECT Id FROM TvNetworks WHERE Name='NBC'))");
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.Sql("DELETE FROM TvNetworks WHERE Name IN ('Netflix', 'HBO', 'CBS', 'NBC')");
        }
    }
}

编辑完成后保存,并更新到数据库。

注意:执行 dotnet ef database update 出现异常,发现之前在编辑字段时,错误的将TvNetworkId 写成了TvNetwordId ,此时需要移除当前 migration内容,修改后,提交一次修改 migration,然后更新数据库成功后,再进行操作。

建立WEB API

在Controllers文件夹下建立TvController.cs.

需要注入TvContext, 这时候聚焦到context变量上使用ctrl+.这个快捷键 生成一个field:

创建好后,添加一个Get 方式的API:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using System.Collections.Generic;
using ANCWEB.Models;
using ANCWEB.Database;

namespace ANCWEB.Controllers
{
    public class TvContoller : Controller
    {
        private readonly TvContext context;

        public TvContoller(TvContext context)
        {
            this.context = context;
        }

        [HttpGet("/api/tvnetworks")]
        public async Task<IEnumerable<TvNetwork>> GetTvNetworks()
        {
            return await context.TvNetworks.Include(x => x.TvShows).ToListAsync();
        }
    }
}

运行,尝试请求会发现并没有返回结果,而且终端出现异常,原因在于一个Tvnetwork有个导航属性是多个TvShow, 而一个TvShow还有一个反向导航属性是TvNetwork, 所以dbcontext查询出来在进行json转化的时候, 会无限循环下去, 就引起了self referencing loop.

建立ViewModel

建立ViewModels/TvNetworkViewModel.csTvShowViewModel.cs:

using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Tv.ViewModels
{
    public class TvNetworkViewModel
    {
        public TvNetworkViewModel()
        {
            TvShows = new Collection<TvShowViewModel>();
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection<TvShowViewModel> TvShows { get; set; }
    }
}
namespace Tv.ViewModels
{
    public class TvShowViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int TvNetworkId { get; set; }
    }
}

注意TvShowViewModel里面并没有反向的TvNetWork属性, 这也保证了不会发生上面的自身循环引用异常.

接下来需要做的就是在Controller里面把Domain Model的属性传递给ViewModel, 没人会去手写这个映射的过程, 所以应该使用AutoMapper等类似的库。

AutoMapper

首先添加AutoMapper, 一共有两个包:

dotnet add package AutoMapper
dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection

别忘了还要执行dotnet restore.

安装成功后:

  • Startup.cs里面注册AutoMapper,
services.AddAutoMapper();
  • AutoMapper还需要知道Domain Model和ViewModel的对应关系和方向.
using AutoMapper;
using Tv.Models;
using Tv.ViewModels;

namespace Tv.Mapping
{
    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<TvNetwork, TvNetworkViewModel>();
            CreateMap<TvShow, TvShowViewModel>();
        }
    }
}
  • 然后在Controller里面需要注入AutoMapper
using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Tv.Database;
using Tv.Models;
using Tv.ViewModels;

namespace Tv.Controllers
{
    public class TvController : Controller
    {
        private readonly TvContext context;
        private readonly IMapper mapper;

        public TvController(TvContext context, IMapper mapper)
        {
            this.context = context;
            this.mapper = mapper;
        }

        [HttpGet("/api/tvnetworks")]
        public async Task<IEnumerable<TvNetworkViewModel>> GetTvNetworks()
        {
            var models = await context.TvNetworks.Include(x => x.TvShows).ToListAsync();
            var vms = mapper.Map<List<TvNetwork>, List<TvNetworkViewModel>>(models);
            return vms;
        }
    }
}

修改后调试,使用Postman获取数据如下:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 腾讯云人脸检索引入教程

    用大白话来说,就是从一张合影中,匹配出与默认添加个体最相似的一个个体(API会给出最高的五个,从匹配度由高到低排列)。

    李郑
  • node.js 学习笔记

    node.js学习笔记 最近一直在折腾前端,为了方便前端学习,所以打算顺带捡一下之前看过一点的node.js,也就顺手MarkDown一个学习笔记。 no...

    李郑
  • SQLServer T-SQL 部分查询语句归纳

    通过某一约束条件 (ON table.XXX = table2.XXX) 进行关联,如果表中有至少一个匹配,则返回行,输出查询的字段。

    李郑
  • 数据库相关总结

    通用: http://db-engines.com/en/ranking MySQL MySQL: http://www.mysql.com/ MySQL参考:...

    用户1221057
  • C语言操作excel表格-链表实现

    https://blog.csdn.net/morixinguan/article/details/83309576

    morixinguan
  • 【安恒信息每日资讯2016.04.04】

    1.直击Black Hat Asia黑帽亚洲峰会:无人机又飞走了 http://www.freebuf.com/news/100625.html 没...

    安恒信息
  • 快播王欣出狱后首次露面 与姚劲波聊AI视频区块链

    我们都欠快播一个会员,还记得吗? 快播成立于2007年,至今已经九个年头了!快播曾给大众带来欢愉的免费良心软件,毫不夸张的说快播是一代互联网的记忆。如果说少年...

    区块链领域
  • NodeJS源码解析--Node如何处理HTTP请求

    看过我之前的写的文章的朋友们应该会知道,使用NodeJS创建一个HTTP服务器是非常简单的。我们写的一个个API中使用req来接收请求,使用re...

    逆月翎
  • 软件登记证书好处?

    软件登记证书 是对登记著作权的初步证明,更是合法的证明文件,有了这张证明可谓 “有百利而无一害”:

    京汨 Jingmis.com
  • ClickHouse源码导读:网络IO

    ClickHouse是一款开源的列式数据库,主要应用于在线分析查询场景(OLAP)。其显著特点就是:性能强悍。

    fastio

扫码关注云+社区

领取腾讯云代金券