SQL Server数据库中的表名称、字段比较

前言

原文 Adding a New Field
作者 Rick Anderson
翻译 谢炀
校对 许登洋、高嵩

项目中一般分测试环境,生产环境,当我们的项目经历了一次周期跨度较长的更新后,当我们发布到生产环境时,首要的任务是将新增的表,字段更新到生产数据库。很多时候,当我们发布更新的时候,已经很难记得做了哪些变更。

在这个章节你将使用 Entity Framework Code First
迁移模型中新加的字段,从而将模型字段变更同步到数据库。

当然有的人会说,1.EF Code First
有history记录,这是一种办法,可靠么?不可靠。相信即便是用Code
First,直接改数据库的肯定不止我一个。

当你使用 EF Code First 模式自动创建一个数据库,Code First
模式添加到数据库的表将帮助你来跟踪数据库的数据结构是否和从它生成的模型类是同步的。如果不同步,EF
会抛出异常。这将有助于你在开发阶段就发现错误,否则可能要到运行时才能发现这个错误了(通过一个很隐蔽的错误信息)。

2.查看实体类变更记录,这也是一个办法。那如果用的DB
First的呢?当然也可以看,就是很麻烦。

添加一个 Rating 字段到 Movie 模型

打开 Models/Movie.cs 文件,添加一个 Rating 属性:

public class Movie{    public int ID { get; set; }    public string Title { get; set; }    [Display(Name = "Release Date")]    [DataType(DataType.Date)]    public DateTime ReleaseDate { get; set; }    public string Genre { get; set; }    public decimal Price { get; set; }    public string Rating { get; set; }  //手动高亮}

生成应用程序(Ctrl+Shift+B)。

因为你已经在 Movie 类添加了一个新的字段,你还需要更新绑定的白名单,这样这个新的属性将包括在内。为了 Create 和 Edit action
方法包含 Rating 属性需要更新 [Bind] 特性:

[Bind("ID,Title,ReleaseDate,Genre,Price,Rating")]

为了把这个字段显示出来你必须更新视图,在浏览器视图中创建或者编辑一个新的 Rating 属性。

编辑 /Views/Movies/Index.cshtml 文件并添加一个 Rating 字段:

<table class="table">    <tr>        <th>            @Html.DisplayNameFor(model => model.movies[0].Genre)        </th>        <th>            @Html.DisplayNameFor(model => model.movies[0].Price)        </th>        <th>            @Html.DisplayNameFor(model => model.movies[0].ReleaseDate)        </th>        <th>            @Html.DisplayNameFor(model => model.movies[0].Title)        </th>        <th>            @Html.DisplayNameFor(model => model.movies[0].Rating) <!--手工高亮-->        </th>        <th></th>    </tr>    <tbody>        @foreach (var item in Model.movies)        {            <tr>                <td>                    @Html.DisplayFor(modelItem => item.Genre)                </td>                <td>                    @Html.DisplayFor(modelItem => item.Price)                </td>                <td>                    @Html.DisplayFor(modelItem => item.ReleaseDate)                </td>                <td>                    @Html.DisplayFor(modelItem => item.Title)                </td>                <td>                    @Html.DisplayFor(modelItem => item.Rating) <!--手工高亮-->                </td>

更新 /Views/Movies/Create.cshtml 文件添加 Rating 字段。你可以从上一个 form group 拷贝/粘帖以便于让智能感知帮助你更新字段。智能感知参考 Tag
Helpers。
澳门贵宾会注册送豪礼 1

应用程序无法工作,直到我们更新了数据库包含新的字段。如果你现在运行程序,你将得到下面的
SqlException :
澳门贵宾会注册送豪礼 2

你看到这个错误是因为更新过的 Movie 模型类与数据库中存在的 Movie
的结构是不同的。(数据库表中没有 Rating 列)

有以下几种方法解决这个错误:

  1. 澳门贵宾会注册送豪礼,Entity Framework
    可以基于新的模型类自动删除并重建数据库结构。在开发环节的早期阶段,当你在测试数据库上积极做开发的时候,这种方式是非常方便的;它可以同时让你快速地更新模型类和数据库结构。但是,缺点是你会丢失数据库中的现有的数据
    ——
    因此你不想在生产数据库中使用这种方法!使用初始化器自动完成数据库的初始化并填充测试数据,往往是开发应用程序的一个有效方式。

  2. 显式修改现有数据库的结构使得它与模型类相匹配。这种方法的好处是,你可以保留录入过的数据。你可以手动修改或通过执行一个自动创建的数据库更改脚本进行变更。

  3. 采用 Code First 迁移来更新数据库结构。

对于本教程,我们采用 Code First 迁移。

更新 SeedData 类以便于为新的的字段提供填充值。下面展示一个变更的例子,但是你可能希望将这个变更应用到每个 new Movie

new Movie{     Title = "When Harry Met Sally",     ReleaseDate = DateTime.Parse("1989-1-11"),     Genre = "Romantic Comedy",     Rating = "R", //手动高亮     Price = 7.99M},

生成解决方案,然后打开命令提示符。输入以下命令:

dotnet ef migrations add Ratingdotnet ef database update

migrations add 命令通知数据库迁移框架检查 Movie 模型是否与当前 Movie 数据库表结构一致,如果不一致,就会创建新的必要的代码把数据库迁移到新的模型。“Rating”
名字可以是任意的,只是用于迁移文件。对于迁移操作采用有意义的名字是有帮助的。

如果在数据库中删除所有记录,数据库将会被初始化并添加 Rating 字段。你可以在浏览器或者
SSOX ( 即SQL Server Object Explorer(SQL
Server对象资源管理器),译者注)中点击删除链接。

运行应用程序并验证你可以用 Rating 字段 create/edit/display
电影。你还应该将 Rating 字段添加到
EditDetails 和 Delete 视图模板中。

返回目录

3.开发过程中,对数据库的变更记下来。这么做过的肯定也不止我一个。手动狗头

。。。。。

中午的时候,就想着另外一个项目下个月要更新,改了N多的东西,到时候数据库咋更新呢。就想着写个工具比较两个版本数据库,表名称,字段,字段类型的区别。

说干就干。

控制台应用程序,目前只能对比新增,修改。

using System;using System.Collections.Generic;using System.Data.SqlClient;using System.Linq;using System.Text;using Microsoft.EntityFrameworkCore;namespace EFGetTable{ class Program { static void Main(string[] args) { string prdconnectionstring = "Data Source=localhost;initial catalog=ttPRD;user id=sa;password=password;MultipleActiveResultSets=True"; var prd = GetTableNames(prdconnectionstring); string qasconnectionstring = "Data Source=localhost;initial catalog=ttqas;user id=sa;password=password;MultipleActiveResultSets=True"; var qas = GetTableNames(qasconnectionstring); CompareTable(prd, qas); } public static ListTableInfo GetTableNames(string connectionstr) { var tableresult = new ListTableInfo(); string sqlTableName = "Select * From Information_Schema.Tables"; using (SqlConnection connection = new SqlConnection(connectionstr)) { using (SqlCommand cmd = new SqlCommand(sqlTableName, connection)) { try { connection.Open(); SqlDataReader dr = cmd.ExecuteReader();// while (dr.Read()) { // 表名 TableInfo table = new TableInfo(); table.TableName = dr["Table_Name"].ToString(); table.columns.AddRange(GetColumnNamesByTable(dr["Table_Name"].ToString(), connection)); tableresult.Add(table); } connection.Close(); } catch (System.Data.SqlClient.SqlException e) { Console.ForegroundColor = ConsoleColor.Red; Console.Error.WriteLine(e.Message); connection.Close(); } } return tableresult; } } public static ListCloumnInfo GetColumnNamesByTable(string tableName, SqlConnection connection) { var Columnresults = new ListCloumnInfo(); string sqlcolum = $"Select * From Information_Schema.Columns t Where t.Table_Name =\'{tableName}\'"; using (SqlCommand cmd = new SqlCommand(sqlcolum, connection)) { SqlDataReader dr = cmd.ExecuteReader();// while (dr.Read()) { // 表名 CloumnInfo column = new CloumnInfo(); column.CloumnName = dr["Column_name"].ToString(); column.DateType = dr["DATA_TYPE"].ToString() + dr["CHARACTER_MAXIMUM_LENGTH"].ToString(); Columnresults.Add(column); } return Columnresults; } } public static void CompareTable(ListTableInfo prd, ListTableInfo qas) { foreach (var p in qas) { var tablequery = prd.AsQueryable().Where(t = t.TableName.Equals(p.TableName)); if (!tablequery.Any()) { Console.WriteLine($"New Created Table {p.TableName}"); continue; } else { var querytable = tablequery.FirstOrDefault(); p.columns.ForEach(c = { var Cloumnquery = querytable.columns.Select(cc = cc.CloumnName).Contains(c.CloumnName); if (!Cloumnquery) { Console.WriteLine($"New add cloumn: {c.CloumnName} on Table {p.TableName}"); } else { var querycloumn = querytable.columns.Where(qt = qt.CloumnName.Equals(c.CloumnName)).FirstOrDefault(); if (!querycloumn.DateType.Equals(c.DateType)) { Console.WriteLine($"DateType Different: cloumn: {c.CloumnName} , {querycloumn.DateType}=={c.DateType} on Table {p.TableName}"); } } }); } } } } public class TableInfo { public TableInfo() { columns = new ListCloumnInfo(); } public string TableName { get; set; } public ListCloumnInfo columns { get; set; } } public class CloumnInfo { public string CloumnName { get; set; } public string DateType { get; set; } }}

测试结果

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

发表评论

电子邮件地址不会被公开。 必填项已用*标注