项目简述
这个项目是我在学习.Net Core编程的时候用到的简单例子,整体就是通过Get请求获取某地区的天气信息,经过json反向序列化后写入到数据库中存储起来。通过.net6的EntityFramework我们可以很优雅地为这个小项目进行CodeFirst的设计(沿用杨中科老师的一个观点:“关系型数据库对程序员来讲只是一个存放数据模型的媒介,理想状态下程序员不用关心数据库的操作。”)这个项目将会用EntityFramework进行数据库的CURD操作,任务目标:
- 获取和风天气接口的数据
- 解析数据并进行数据库插入动作
配置条件
- DotNetCore控制台应用(.Net 6.0)
- Microsoft SQL Server 2022
- Nuget Packages
- EntityFrameworkCore.SqlServer(version6.0.25)
- EntityFrameworkCore.Tools(version6.0.25)
- 和风天气Qweather开发服务 (可免费订阅)
关于关系型数据库:
对于SQL Server数据库安装配置,请自行谷歌。
关于和风天气Qweather开发服务:
和风天气免费订阅的接口地址是:
https://devapi.qweather.com/v7/weather/3d?location={LocationCode}&key={Key}
通过简单的Get请求即可获得天气信息结构体,但注意和风天气开发服务的API均使用Gzip进行了压缩,代码中要进行解压处理。详细信息参考官方的开发文档。同时城市代码可以在这个Github仓库当中查询得到。接口返回的json如下
{
"code": "200",
"updateTime": "2023-12-07T14:47+08:00",
"fxLink": "https://www.qweather.com/weather/beijing-101010100.html",
"now": {
"obsTime": "2023-12-07T14:38+08:00",
"temp": "8",
"feelsLike": "5",
"icon": "504",
"text": "浮尘",
"wind360": "30",
"windDir": "东北风",
"windScale": "2",
"windSpeed": "10",
"humidity": "30",
"precip": "0.0",
"pressure": "1000",
"vis": "6",
"cloud": "0",
"dew": "-8"
},
"refer": {
"sources": [
"QWeather"
],
"license": [
"CC BY-SA 4.0"
]
}
}
代码框架设计
创建基础代码框架
通过Visual Studio 2022新建一个C#控制台应用,注意不要选.Net Framework。框架选择.Net 6.0(长期支持)。当然如果想学习.NET 8也可以积极尝试~
对于这次任务用到的数据模型Models有:
- 和风天气数据模型
- 城市昵称及其对应的代号
创建城市代码字典
我们可以在解决方案目录下新建Model文件夹(本文假设你的解决方案昵称是WeatherCollectorConsole),,在Model文件夹中新建CityCode文件,我们用Dictionary存放string对象的城市昵称,用int对象存放对应城市代码。代码如下:
namespace WeatherCollectorConsole.Models
{
public class CityCode
{
public readonly Dictionary<string, int> cityCodeDict = new()
{
{"北京", 101010100},
{"上海", 101020100}
};
}
}
创建和风天气接口的数据模型
对于和风天气的json格式,我们在Model文件夹中另行新建QWeatherjson文件,通过类去建立起数据模型。代码如下:
namespace WeatherCollectorConsole.Models
{
public class QWeatherAPIjson
{
public string code { get; set; }
public string updateTime { get; set; }
public string fxLink { get; set; }
public WeatherDetails now { get; set; }
public Refer refer { get; set; }
}
public class WeatherDetails
{
public string obsTime { get; set; }
public string temp { get; set; }
public string feelsLike { get; set; }
public string icon { get; set; }
public string text { get; set; }
public string wind360 { get; set; }
public string windDir { get; set; }
public string windScale { get; set; }
public string windSpeed { get; set; }
public string humidity { get; set; }
public string precip { get; set; }
public string pressure { get; set; }
public string vis { get; set; }
public string cloud { get; set; }
public string dew { get; set; }
}
public class Refer
{
public List<string> sources { get; set; }
public List<string> license { get; set; }
}
}
注意到,这里类中的每“项”的名称都应该和json的物件名称一一对应,这会在后面存放数值提供大大的方便。
配置EntityFramework环境
对于本文的.NET6.0框架,请在解决方案处右键-选取“管理Nuget程序包”,检索下列nuget包昵称及版本进行安装
- EntityFrameworkCore.SqlServer(version6.0.25)
- EntityFrameworkCore.Tools(version6.0.25)
如果是.Net 8.0的项目,就安装对应的version8.x 配置CodeFirst的EntityFramework环境大概需要三类代码:
- 数据表类的声明
- 数据表的配置
- 数据库的操作
数据表WeatherTable的声明
我们可以在Models文件下中建立声明(因为本质上都是一种数据模型~),新建WeatherTable.cs文件,键入代码:
using System.ComponentModel.DataAnnotations;
namespace WeatherCollectorConsole.Models
{
public class WeatherTable
{
[Key]
public long Id { get; set; }
public DateTime DataUpdateTime { get; set; }
public string CityName { get; set; }
public DateTime ObsTime { get; set; }
public int? Temp { get; set; }
public int? TempFeelsLike { get; set; }
public string? WeatherText { get; set; }
public int? Wind360 { get; set; }
public string? WindDir { get; set; }
public int? WindScale { get; set; }
public int? WindSpeed { get; set; }
public int? Humidity { get; set; }
public double? RainPrecip { get; set; }
public int? Pressure { get; set; }
public int? Vis { get; set; }
public int? Cloud { get; set; }
public int? Dew { get; set; }
}
}
注意到:
- 采用了DataAnnotations标注自增种子主键key
- 类中声明的变量类型会通过EF(EntityFrameworkd的缩写)对数据库对应的变量类型进行设计,当然可以后续我们可以微调
数据表的配置
数据表的配置建议新建Config代码文件,后续进行代码的维护。新建WeatherTableConfig.cs文件,键入代码:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using WeatherCollectorConsole.Models;
namespace WeatherCollectorConsole
{
class WeatherTableConfig:IEntityTypeConfiguration<WeatherTable>
{
public void Configure(EntityTypeBuilder<WeatherTable> builder)
{
builder.ToTable("WeatherTable");
}
}
}
这个代码是EF通过WeatherTable类确定好数据表的设计,所以就称呼为“数据表的配置代码”。EF对数据表的约定是以保证不会爆的前提下进行的,如string对应的nvchar长度多少好呢?肯定是max不会爆啊~为了环保主义,我这里会对城市名称CityName、天气状况WeatherText、风向WindDir三个项目限制长度,并对数据更新时间DataUpdateTime(当作数据写入数据库的时间,非数据观测/检测的时间)要求不能为空。将会对builder额外加入属性要求:
builder.Property(b=>b.CityName).HasMaxLength(25).IsRequired();
builder.Property(b=>b.DataUpdateTime).IsRequired();
builder.Property(b=>b.WeatherText).HasMaxLength(30);
builder.Property(b => b.WindDir).HasMaxLength(30);
整体代码如下:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using WeatherCollectorConsole.Models;
namespace WeatherCollectorConsole
{
class WeatherTableConfig:IEntityTypeConfiguration<WeatherTable>
{
public void Configure(EntityTypeBuilder<WeatherTable> builder)
{
builder.ToTable("WeatherTable");
builder.Property(b=>b.CityName).HasMaxLength(25).IsRequired();
builder.Property(b=>b.DataUpdateTime).IsRequired();
builder.Property(b=>b.WeatherText).HasMaxLength(30);
builder.Property(b => b.WindDir).HasMaxLength(30);
}
}
}
数据库物件的建立
在解决方案中新建WeatherDBContext.cs文件,键入以下代码:
using Microsoft.EntityFrameworkCore;
using WeatherCollectorConsole.Models;
namespace WeatherCollectorConsole
{
class WeatherDBContext:DbContext
{
public DbSet<WeatherTable> WeatherTables { get;set;}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer("Server=serveraddress,port;Database=database;User ID=username;Password=password");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
}
}
对于一个练手程序我们暂且通过hardcore并明文保存数据库连接字符串…而且我当你是已经解决好数据库的连接问题的了… 简单看一下这段代码的意义:
- 声明WeatherDBContext这个类继承EF的DbContext
- WeatherDBContext中通过DbSet加载你定制的各种数据表的结构
- OnModelCreating方法中的ApplyConfigurationsFromAssembly可以自动获取DbSet中的T的类型
- OnConfiguring用于开启你的数据库的连接..
CodeFirtst!
CodeFirtst是最精髓的操作~对于这种非生产型的小项目可能会有无数改动,我们通过修改WeatherTable的定义就可以快速同步修改数据库的数据类型,无论增减还是删库跑路都不用麻烦其他的同事~具体我们会用到EntityFrameworkCore.Tools的Migration进行操作: 首先找到Visual Studio的程序包管理器控制台,如果没有的话在“视图-其他窗口-程序包管理器控制台”可以找到。 请注意Migration这个“迁移”操作需要当前代码能够正常通过编译。排除代码的错误后在程序包管理器控制台键入命令:
Add-Migration MigrationName
请把MigrationName改成实际有意义的remark,Migration操作会在Migration文件夹下生成Datetime_MigrationName.cs文件用于区分每次“迁移”,当Migration命令正常执行后,可以通过SSMS查看得数据库并没有任何变化。这是因为“迁移”命令并没有对数据库执行任何SQL指令。此时,在程序包管理器控制台键入命令:
Update-database
数据库就会神奇地按照WeatherTable所声明的形式建立起数据表。
小结
在本文中我们配置了数据库的连接方式,并借用EF轻松地执行了数据库的操作。下文我们将会进行数据的获取与写入库的操作。
引用及参考
-
杨中科.NET6视频教程2022版https://www.youtube.com/playlist?list=PL9sJKk6XPMxehYCui7OysUV6trlBbJ4T_
-
杨中科.NET6视频教程Part3-EFCore-2-忘掉DBFirst吧,正确搭建Entity Framework Corehttps://www.youtube.com/watch?v=cPpim_K2h9g