Dark Mode 亦称为 暗黑模式、黑暗模式、暗色模式、黑夜模式、深夜模式、夜间模式 等,以下介绍几种常用软件的 Dark Mode 的设置方法。
iOS:
【iOS 13+】在 设置 - 显示与亮度 - 选择“深色”
【iOS 11+】在 设置 - 通用 - 辅助功能 - 显示调节 - 反转颜色 中开启“智能反转”。
“智能反转”缺点:第三方应用上显示的图片会以“经典反转”的方式展示。
Android:
设置 - 显示 - 主题模式,选择“暗色主题”
版本支持:Android 9.0 - Pie(Android P)
macOS:
系统偏好设置 - 通用 - 外观,低版本系统中勾选“使用暗色菜单栏和 Dock”,高版本系统中直接点击预览图选择主题。
版本支持:在 OS X Yosemite 10.10 中提供支持,在 macOS Mojave 10.14 中全新升级。
Windows:
桌面右键“个性化”(或从 Windows 设置中打开),在“颜色”选项卡,选择默认应用模式“暗”。
版本支持:Windows 10 October 2018 Update(版本 1809)
Microsoft Office:
文件 - 选项 - 常规 - Office 主题:黑色
在一个组件中设置后(如 Word),会在其它的组件中同时生效(如 Excel)。但 Visio 没有“黑色”主题(至少在 2019 中),我尝试更改为“深灰色”,Word 也变为“深灰色”,然后在未关闭 Visio 的情况下再次更改 Word 为“黑色”,Visio 界面竟然也变成了“黑色”,设置选项中为空白。
版本支持:Office 2016
Adobe Photoshop:
点开 菜单:编辑 - 首选项 - 界面,根据自已喜爱更改颜色方案。
版本支持:Photoshop CS6(可能更早),新版中已默认启用
CorelDRAW:
点开菜单:工具 - 选项,左侧展开 工作区 - 外观,主题选择“暗”或“黑体”。
版本支持:CorelDRAW X8(可能更早)
Microsoft Visual Studio:
点开菜单:工具 - 选项 即可更改颜色主题为“深色”(左侧选项卡为 环境-常规)。
版本支持:Visual Studio 2012
微信开发者工具:
点开菜单:设置 - 外观设置,选择“深色主题”
仅在文件代码面板有效
Microsoft Edge:
设置 - 自定义 - 选择一个模式 - 暗
Chrome:
在 Chrome 74 版本中支持。
其开发者工具(F12)早在 50 版本中已提供 Dark 主题,在开发者工具右上角展开竖状三点图标 - Settings - Theme: Dark
Windows 的 Chrome 的 Dark 模式无需设置,会根据 Windows 自身是否为暗模式来调整。
因其 Dark 模式不容易区分当前标签页,如需禁用 Dark 模式,参此文
Adobe Acrobat Reader DC:
点开菜单:视图 - 显示主题 - 深灰
HBuilder X:
点开菜单:工具 - 主题 - 酷黑
Code Write:
设置 - Editor - Theme - Dark(默认已启用)
前言:
本文适合 6.x 环境,8.x 请结合参考:如何升级 ASP.NET 项目 MySql.Data 和 Connector/NET 至 8.0.x
使用 ASP.NET Core 的同学请移步:ASP.NET Core 使用 DBFirst 模式连接 MySQL 数据库
安装
开发环境
软件安装:
MySQL for Visual Studio - 用于在 Visual Studio 中连接 MySQL 数据库
Connector/NET - ADO.NET 托管提供程序
Nuget 中搜索安装 MySql.Data 和 MySql.Data.Entity
版本选择:
MySQL for Visual Studio 最新版
Connector/NET 版本必须与 MySql.Data 和 MySql.Data.Entity 版本相同,否则会出现 MySql.Data.MySqlClient.MySqlConnection 无法强制转换的错误
生产环境
软件安装:
MySQL Server - 数据库
Connector/NET - ADO.NET 托管提供程序
版本选择:
MySQL Server 最新版
Connector/NET 应与项目中使用的 MySql.Data 和 MySql.Data.Entity 版本一致。(某些项目在确保 Web.config 的 MySql.Data 版本号与 MySql.Data 和 MySql.Data.Entity 版本一致的前提下,允许服务端的 Connector/NET 小版本略低于 MySql.Data 和 MySql.Data.Entity 版本,某些项目允许安装比 MySql.Data 和 MySql.Data.Entity 版本略高的 Connector/NET 版本,为确保不出问题,严格要求版本全部一致)
升级
MySQL for Visual Studio:直接更新至最新版
MySQL Server:直接更新至最新版
MySql.Data 和 MySql.Data.Entity:升级至两者共有的新版本,更改 Web.config 中 MySql.Data 的版本号,并更新开发环境和生产环境的 Connector/NET 至相同版本(详细步骤见下方说明)
Connector/NET:视是否有相同版本的 MySql.Data 和 MySql.Data.Entity,若有,同时升级。(详细步骤见下方说明)
关于 Connector/NET 和 MySql.Data 及 MySql.Data.Entity 版本一致的说明:
某些项目在确保 Web.config 的 MySql.Data 版本号与 MySql.Data 和 MySql.Data.Entity 版本一致的前提下,允许服务端的 Connector/NET 小版本略低于 MySql.Data 和 MySql.Data.Entity 版本;
某些项目允许安装比 MySql.Data 和 MySql.Data.Entity 版本略高的 Connector/NET 版本;
为确保不出问题,严格要求版本全部一致。
但服务器上同时运行多个项目,一旦出现问题涉及面就很广,为了尽量减少影响,列出下面的升级步骤:
升级开发环境的 Connector/NET
升级各项目的 MySql.Data 和 MySql.Data.Entity
更改 Web.config 中关于 MySql.Data 的版本号(若未自动更新,项目中搜索原版本号即可)
测试运行各项目
同时发布各项目,同时升级服务器上的 Connector/NET(升级 Connector/NET 仅需几十秒)
部分项目需要删除并重新上传 bin 目录才能生效
尽管如此,发布成功以后还是会有各种各样的问题导致无法正常打开,须要有针对性地去解决,所以升级还是要趁夜深人静的时候进行
重点提前看:
https://xoyozo.net/Blog/Details/MySQL-on-Windows
Connector/Net 6.10.4(暂)不支持在 Visual Studio 2015/2017 添加 ADO.NET 实体数据模型时选择 MySQL Data Provider 数据源。并且,在编译项目时会出现“违反了继承安全性规则”的异常。
只能降回 Connector/Net 6.9.10,NuGet 中将 MySql.Data 和 MySql.Data.Entity 用 6.9.10 和 6.10.4 版本皆可(除非遇到下文中提到的异常)。
重新生成或重启 VS 使之生效。
另外,MySql.Data 和 MySql.Data.Entity 6.9.10 可以配合 EnityFramework 和 EntityFramework.zh-Hans 6.1.x 和 6.2.0 使用。
MySql.Data 和 MySql.Data.Entity 6.9.9 在创建/更新实体模型向导中会出现闪退,更换为 6.9.10 试试。
或重新安装 Connector/NET 和 MySQL for Visual Studio 并重启电脑试试。
仍然闪退,参此文:https://xoyozo.net/Blog/Details/mysql-for-vs-flashback。
重要提醒,如果在添加 EF 模型时报错:
您的项目引用了最新版的实体框架;但是,找不到进行数据连接所需的与此版本兼容的实体框架数据库提供程序。请退出向导,安装兼容提供程序,重新生成您的项目,然后再执行此操作。
那么在菜单中选择:生成 - 清理解决方案,然后直接添加数据模型。如果在添加前生成了项目(bin 目录下有相关 .dll 文件),那么将出现上述错误。
类型“MySql.Data.MySqlClient.MySqlProviderServices”违反了继承安全性规则。派生类型必须与基类型的安全可访问性匹配或者比基类型的安全可访问性低。
将 MySql.Data 和 MySql.Data.Entity 从 6.10.4 退回 6.9.10 版本即可。
以上问题出现在:
VS 15.4.*
VS 15.4.4
VS 15.4.5
----------------
VS 15.5 已经可以在 EF 向导中连接 MySQL 数据库(Connector/Net 6.10.4),但 MySql.Data.Entity 6.10.4 编译仍然出现“违反了继承安全性规则”。另:MySQL 官网下架了 Connector/Net 6.10.4,退回提供 6.9.10 版本。
2017-12-9 发布的 Connector/Net 6.10.5 仍然存在无法在 EF 向导中连接 MySQL 数据源的问题。
服务器上安装 Connector/Net 6.10.4 没有任何问题。
在 Windows 上安装 MySQL Server,提示需要安装 Microsoft Visual C++ 2013 Redistributable,但 MySQL Installer 安装向导中提供的 C++ 是 12.0.30501 版本:
导致无法正常安装 MySQL Server,仍然提示:
This application requires Visual Studio 2013 Redistributable. Please install the Redistributable then run this installer again.
解决办法是下载安装 Update for Visual C++ 2013 and Visual C++ Redistributable Package,即 12.0.40649.5 版本
安装成功
如果在 Visual Studio 2017 中打开 LINQ To SQL 的 .dbml 文件时是以 XML 的方式打开的,那么需要安装“LINQ to SQL tools”,步骤如下:
1,关闭 VS
2,运行 VS 安装程序
3,修改
4,切换到“单个组件”选项卡,勾选“LING to SQL 工具”
5,确认修改
官方教程:Getting started with ASP.NET Core MVC and Entity Framework Core using Visual Studio
第一课:入门
Entity Framework Core NuGet 软件包
安装数据库提供程序(以 SQL Server 为例):其它数据库提供程序
Install-Package Microsoft.EntityFrameworkCore.SqlServer
该软件包依赖 Microsoft.EntityFrameworkCore 和 Microsoft.EntityFrameworkCore.Relational
新建数据模型
文件夹 Models 存放实体类
默认以 ID 或 类名ID 为主键列,并且是标识(即自动递增),以下代码可以取消标识,允许自定义 ID 值
[DatabaseGenerated(DatabaseGeneratedOption.None)]
导航属性:对于数据库来说就是外键,对一定义为实体类,对多定义为 ICollection<T>
字段类型可以是枚举 enum
创建数据库上下文
在 Data 文件夹中创建一个名为 SchoolContext.cs 的类,继承于 DbContext
使用依赖注入注册上下文
修改 Startup.cs 的 ConfigureServices 方法
在 appsettings.json 中配置数据库连接字符串
添加代码以使用测试数据初始化数据库
在 Data 文件夹中创建一个名为 DbInitializer.cs 的类
修改 Startup.cs 的 Configure 方法
新建一个控制器和视图
在 Controllers 文件夹上右键,添加
MVC 依赖项选择 Minimal Dependencies 即可
会自动安装 NuGet 包:Microsoft.EntityFrameworkCore.Design 和 Microsoft.EntityFrameworkCore.SqlServer.Design
公约
表名优先来自 DbSet 属性名,其次是类名
实体属性名将映射为列名
实体属性名 ID 或 类名ID 将默认被设为主键
如果属性被命名,它将当作外键(例如,导航属性 Student 对应的实体 Student 的主键是 ID,所以 StudentID 是外键);
公约可以被覆盖,例如,可以指定表名,设置列名,并将任何属性设置为主键或外键。
异步代码
第二课:新建、读取、更新和删除操作(CRUD)
自定义详细信息页面
Include() // 加载导航属性
ThenInclude() // 加载导航属性的导航属性
AsNoTracking() // 使该实体在当前上下文生命周期中不更新
SingleOrDefaultAsync() // 异步检索单个实体
路由数据
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a>
<a asp-action="Edit" asp-route-studentID="@item.ID">Edit</a>
生成为
<a href="/Students/Edit/6">Edit</a>
<a href="/Students/Edit?studentID=6">Edit</a>
改进“新建页面”
在 HttpPost 的 Create 方法中,因为 ID 是自动递增的,所以可以从 Bind 中删除
[ValidateAntiForgeryToken] 搭配 if (ModelState.IsValid),用于实现验证,防止 CSRF 攻击
改进“删除页面”
在 HttpGet 的 Delete 方法中增加参数用于传递报错内容
在 HttpPost 的 Delete 方法中删除失败则 RedirectToAction 到 Delete 页面并带上报错参数
用”初始化和附加“的方法实现删除
Student studentToDelete = new Student() { ID = id };
_context.Entry(studentToDelete).State = EntityState.Deleted;
实例化要删除的实体(仅指定主键值),并将状态设置为 Deleted,即可在 SaveChanges 时实现删除,从而避免了删除必须先读取的情况。
处理交易
当 SaveChanges 时,EF 自动确保所有更改都成功或都失败,如果首先完成一些更改,然后发生错误,那么这些更改将自动回滚。
无追踪查询
什么情况下适用 AsNoTracking 方法:
在上下文中不需要更新任何实体,并且不需要加载导航属性(若需要导航属性,可以预先 Include 或稍后单独查询)
检索大量数据时,仅一小部分将被更新(稍后单独查询)
当前检索的实体需要在稍后以不同的目的附加(_context.Entry(*).State)
第三课:排序,过滤,分布和分组
添加列排序链接到学生索引页
将“搜索框”添加到“学生索引”页面
将分页功能添加到“学生索引”页面
PaginatedList 类的使用
创建一个显示学生统计信息的关于页面
创建视图模型:在 Models 文件夹中创建一个 SchoolViewModels 文件夹,添加一个类文件 EnrollmentDateGroup.cs
修改 HomeController 添加上下文
使用 group by 进行分组查询
第四课:迁移
用于迁移的 NuGet 软件包
要使用迁移,可以使用包管理器控制台(PMC)或命令行界面(CLI)。教程
CLI 的另一种打开方式:在项目上右键 - 在文件资源管理器中打开文件夹,在地址栏上键入 cmd 回车
删除数据库的 CLI 命令
dotnet ef database drop
创建初始迁移
dotnet ef migrations add InitialCreate
创建数据库的代码位于 Migrations 文件夹中,Up 方法用于创建,Down 方法用于回滚
这时只生成了创建数据库的代码,并没有真正的创建数据库
多次创建的迁移会按时间戳的次序展示在 Migrations 文件夹中,数据库中记录了最后一次迁移的版本
检查数据模型快照
迁移会在 Migrations/SchoolContextModelSnapshot.cs 中创建当前数据库模式的快照,因此 EF Core 不必与数据库进行交互以创建迁移。
要删除最后一次迁移,执行:
dotnet ef migrations remove
将迁移应用于数据库
dotnet ef database update
执行完成会创建数据库结构,但表中的初始数据将在第一次运行时被添加。
上次应用迁移之后创建的一个或多个新迁移,将在当前应用迁移时按顺序全部执行。
第五课:创建复杂的数据模型
通过使用属性自定义数据模型
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
DataType 用于指定比数据库固有类型更具体的数据类型,上例指定为日期,而不是日期和时间
DateType 支持:Date, Time, PhoneNumber, Currency, EmailAddress 等等
DateType 支持传达数据的语义到 HTML5
DisplayFormat 用于指定格式
ApplyFormatInEditMode 指定是否当值显示在文本框中进行编辑时也应用此格式
[StringLength(50)]
[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
[RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]
StringLength 设置数据库中最大长度,并为客户端和服务端提供验证
StringLength 可以指定最小长度,但该值对数据库没有影响
StringLength 不会阻止用户输入空格,可以使用 RegularExpression 来限制
缩短最大长度会导致迁移时发出警告,为了保证顺利迁移,请先更改数据或重新选择合适的最大长度
[Column("FirstName")]
public string FirstMidName { get; set; }
上例将属性 FirstMidName 映射到数据库列名 FirstName
[Required]
必需属性,不能为空的类型将自动处理必填字段,无需重复指定。
[Display(Name = "Last Name")]
显示属性,指定用于显示的名称
计算属性,只有一个 get 访问器,不会在数据库中生成列,例如:
public string FullName
{
get
{
return LastName + ", " + FirstMidName;
}
}
可以将多个属性放在一行中:
[DataType(DataType.Date),Display(Name = "Hire Date"),DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
在一对一的关系中,副表的主键名称不以副表实体 classnameID 命名,而以主表实体 classnameID 命名时,用 Key 属性来指定主键:
[Key]
或者需要以除 classnameID 或 ID 外的其它属性为主键,那么可以用 Key
[Range(0, 5)]
指定数值范围
当有相关实体的导航属性时,EF 不要求在数据模型中添加外键属性。详情见教程
[DatabaseGenerated(DatabaseGeneratedOption.None)]
主键值由用户提供,而不是由数据库生成。
[Column(TypeName = "money")]
public decimal Budget { get; set; }
通常不需要列映射,此例将 decimal 类型的属性 Budget 映射为 money 类型的字段 Budget。
部门可能有负责人也可能没有,负责人必定是教师。因此 InstructorID 属性为教师实体的外键,并且可空,导航属性是被命名为 Administrator 的 Instructor 实体。
public int? InstructorID { get; set; }
public Instructor Administrator { get; set; }
通常,EF 允许对不可空的外键进行级联删除以久多对多关系。
例如,如果将 Department.InstructorID 属性定义为不可空,则 EF 将配置级联删除规则,以在删除部门时删除教师。如果我们想保留教师,但业务逻辑要求该 InstructorID 属性确实不可为空,则必须使用以下语句来禁用关系中的级联删除:
modelBuilder.Entity<Department>()
.HasOne(d => d.Administrator)
.WithMany()
.OnDelete(DeleteBehavior.Restrict)
补充,现在设计业务逻辑时会尽量避免删除操作,而使用禁用来代替,以在数据库中永久保留记录。
[DisplayFormat(NullDisplayText = "No grade")]
NullDisplayText 指定当值为 null 时的显示内容
联合主键
在多对多关系(教师到课程)的连接表(CourseAssignment)中,两个外键都不可为空,并且一同唯一标识表的每一行,因此不需要单独的主键,将 InstructorID 和 CourseID 作为一个联合主键。
定义联合主键不能通过使用属性来完成,唯一方法是使用 Fluent API,修改 Data/SchoolContext.cs 的 OnModelCreating 方法:
modelBuilder.Entity<CourseAssignment>().ToTable("CourseAssignment");
modelBuilder.Entity<CourseAssignment>()
.HasKey(c => new { c.CourseID, c.InstructorID });
Fluent API 替代属性
protected override void OnModelCreating(ModelBuilder modelBuilder){
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
在本教程中,您只使用 Fluent API 进行数据库映射,而不能使用属性。您还可以使用 Fluent API 来指定可以使用属性执行的大多数格式化、验证和映射规则。一些属性(如 MinimumLength)不能应用 Fluent API,因为它不会更改数据库模式,它只适用于客户端和服务端验证。
一些开发人员喜欢专门使用 Fluent API,以保持实体类“干净”。当然可以混合使用属性和 Fluent API,但推荐只选择一种方式。如果混合使用,那么 Fluent API 会覆盖属性。
添加迁移
dotnet ef migrations add ComplexDataModel
如果在此时尝试运行命令 database update(不要这样做),您将收到以下错误:
ALTER TABLE语句与FOREIGN KEY约束“FK_dbo.Course_dbo.Department_DepartmentID”冲突。冲突发生在数据库“ContosoUniversity”,表“dbo.Department”,“DepartmentID”列。
这是因为在课程 Course 表增加了一个 DepartmentID 外键,而且是不可空的,又由于课程表中已经存在数据,所以无法 AddColumn。
我们可以创建一个临时部门,然后将它的 DepartmentID 值赋给 Course.DepartmentID 作为默认值。
打开 _ComplexDataModel.cs 文件,注释将 DepartmentID 添加到课程表的代码行,注释之,并在创建 Department 表的代码之后添加创建默认部门和添加 DepartmentID 的代码,详见教程。
第六课:读取相关数据
预先加载、显式加载和延时加载
预先加载:当实体被读取时,相关数据随之被检索。即在单个连接查询中读取所有所需数据。通过 Include 和 ThenInclude 方法实现。
显式加载:当实体首次读取时,不检索相关数据。如果需要再检索相关数据。显式加载会导致多次数据库查询。
延时加载:当实体首次读取时,不检索相关数据。在首次尝试访问导航属性时,将自动检索该导航属性所需的数据。
* 从定义上看“显示加载”和“延时加载”比较类似,详细区别会在学完本课后有具体的了解。
创建一个显示部门名称的课程页面
在课程列表中,每个课程都显示部门名称,因此使用预先加载。
在控制器中使用 Include 和 AsNoTracking
在视图中使用 @Html.DisplayFor(modelItem => item.Department.Name)
创建一个显示课程和报名的教师页面
为教师页面创建一个视图模型 InstructorIndexData.cs
在控制器中多次使用 Include 和 ThenInclude 来预先加载相关数据
第一个 Include 加载办公室(一对零或一)
第二个 Include 加载课程(多对多)和报名课程的学生(多对多)
第三个 Include 加载课程(多对多)和课程所在部门(多对一)
本例中“课程的学生”和“课程的部门”是各自级联 ThenInclude 加载的,不能合并到同一个 Include 的课程中,因为 ThenInclude 不能读取多个分支的导航属性,每个分支都必须使用 Include 从教师实体调用。
在视图中给选择的教师添加 class 样式类
显式加载
去掉 Include 和 AsNoTracking,然后在需要的时候附加相关的实体(上下文.Entry())来实现显式加载,以减少首次读取实体时的数据量。
await 上下文.Entry(单个实体).Collection(x=>x.导航属性).LoadAsync(); // 一对多
await 上下文.Entry(单个实体).Reference(x=>x.导航属性).LoadAsync(); // 一对一
第七课:更新相关数据
课程必须与部门关联,在新建和编辑课程时提供部门的下拉列表。
ViewBag.DepartmentID = new SelectList(departmentsQuery.AsNoTracking(), "DepartmentID", "Name", selectedDepartment);
<select asp-for="DepartmentID" class="form-control" asp-items="ViewBag.DepartmentID">
<option value="">-- Select Department --</option>
</select>
SelectList 为下拉列表创建一个集合,允许指定默认选中项,并传递到 ViewBag。
将 .AsNoTracking() 添加到详细信息和删除方法
“一对零或一”关系:(本例是教师和办公室分配,抑或是文章和正文、学生和档案)
删除教师的办公室分配时,如果原先具有值,则删除办公室分配;
输入教师的办公室分配时,如果原先为空,则创建一个办公室分配;
更改教师的办公室分配时,更改现在有办公室分配值。
如何处理:
在 HttpGet 的 Edit 方法中,Include 办公室实体,并 AsNoTracking
在 HttpPost 的 Edit 方法中,移除除 id 以外的参数(为了不与 HttpGet 的 Edit 冲突,改名为 EditPost,并 ActionName("Edit"))
if (await TryUpdateModelAsync<Instructor>(
instructorToUpdate,
"",
i => i.FirstMidName, i => i.LastName, i => i.HireDate, i => i.OfficeAssignment))
使用模型绑定器的值更新检索到的教师实体。TryUpdateModel 支持更新实体的导航属性。
我们可以直接设置实体的导航属性为 null,以便相关的行将被删除。
第八课:处理并发冲突
悲观并发,即锁定,性能差。
乐观并发:
[Timestamp]
public byte[] RowVersion { get; set; }
添加一个 timestamp 类型的 RowVersion 字段
详见教程
第九课:继承
第十课:进阶专题
调用“返回实体”的查询
为了防止 SQL 注入,使用参数化查询:
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
string query = "SELECT * FROM Department WHERE DepartmentID = {0}";
var department = await _context.Departments
.FromSql(query, id)
.Include(d => d.Administrator)
.AsNoTracking()
.SingleOrDefaultAsync();
if (department == null)
{
return NotFound();
}
return View(department);
}
调用“返回其他类型”的查询
编写 SQL,而非 LINQ:
public async Task<ActionResult> About()
{
List<EnrollmentDateGroup> groups = new List<EnrollmentDateGroup>();
var conn = _context.Database.GetDbConnection();
try
{
await conn.OpenAsync();
using (var command = conn.CreateCommand())
{
string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
+ "FROM Person "
+ "WHERE Discriminator = 'Student' "
+ "GROUP BY EnrollmentDate";
command.CommandText = query;
DbDataReader reader = await command.ExecuteReaderAsync();
if (reader.HasRows)
{
while (await reader.ReadAsync())
{
var row = new EnrollmentDateGroup { EnrollmentDate = reader.GetDateTime(0), StudentCount = reader.GetInt32(1) };
groups.Add(row);
}
}
reader.Dispose();
}
}
finally
{
conn.Close();
}
return View(groups);
}
调用“更新”查询(批量更新)
使用参数化查询批量更新数据,返回受影响行数:
ViewData["RowsAffected"] =
await _context.Database.ExecuteSqlCommandAsync(
"UPDATE Course SET Credits = Credits * {0}",
parameters: multiplier);
检查发送到数据库的 SQL
有时,可以看到发送到数据库的实际 SQL 查询很有帮助。
第一步:设置一个断点
第二步:调试模式运行程序
第三步:在“输出”窗口可以看到 SQL 查询语句
自动变化检测
EF 通过将实体的当前值与原始值进行比较来确定实体如何更改。
一些方法会导致自动更改检测:
DbContext.SaveChages
DbContext.Entry
ChangeTracker.Entries
如果您正在跟踪大量实体,并且您在循环中多次调用上述方法之一,则可以通过临时关闭 AutoDetectChangesEnabled 属性,能显著提升性能。
_context.ChangeTracker.AutoDetectChangesEnabled = false;
从现有数据库反向工程
常见错误
问:ContosoUniversity.dll 由另一个进程使用
答:在 IIS Express 中停止站点。
问:迁移在 Up 和 Down 方法中没有代码
原因:在运行migrations add
命令时有未保存的更改
答:运行migrations remove
命令,保存代码更改并重新运行migrations add
命令。
VS2017 安装程序变革比较大,最近安装了 15.1 (26403.3) 版本后提示重启,重启后再次打开安装程序还是提示需要重启,导致无法进入下一步执行添加、删除、修复组件的操作。
试用了几天以后没有发现这个情况会对开发工作产生影响,那么如果要修改安装组件怎么办呢?我们可以打开 Visual Studio 2017,新建项目,在左侧的“已安装”选项卡的底部点击“打开 Visual Studio 安装程序”:
又可以愉快地玩耍啦!
点不了“修改”?请关闭 Microsoft Visual Studio 2017 的所有实例,然后继续此操作。
最近要做个简单的类似 CNZZ 和百度统计的统计器,不可避免地遇到 JS 文件异步加载 和 给 JS 文件传参 的问题。
参考了 CNZZ 的代码以后,在 Chrome 的控制台发现以下警告:
A Parser-blocking, cross-origin script, http://s4.cnzz.com/stat.php?***, is invoked via document.write. This may be blocked by the browser if the device has poor network connectivity. See https://www.chromestatus.com/feature/5718547946799104 for more details.
Paul Kinlan 给出了解释,是因为使用了 document.write() 的方式输出了 <script src="***" /> HTML DOM,建议改成 document.appendChild() 或 parentNode.insertBefore(),最好的例子就是 Google Analytics。
<!-- Google Analytics -->
<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<!-- End Google Analytics -->
上述 JavaScript 跟踪代码段可以确保该脚本在所有浏览器中加载和异步执行。
加了一些注释,便于理解,官方英文版。
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
// console.log(window['GoogleAnalyticsObject']) // 'ga'
// console.log(i[r]) // undefined
i[r] = i[r] || function () { // i[r] 就是 window['ga'],定义了一个函数
(i[r].q = i[r].q || []).push(arguments) // 往 ga.q 这个数组中增加一项
},
i[r].l = 1 * new Date(); // 时间戳,写法等同于 new Date().getTime()
// console.log(i[r]) // window['ga'] 就是上面那个 function
a = s.createElement(o), // 创建一个 script 元素
m = s.getElementsByTagName(o)[0]; // 文档中的第一个脚本(文档中肯定至少已有一个脚本了)
a.async = 1; // 异步加载
a.defer = 1; // 兼容旧浏览器(我自己加的)
a.src = g;
m.parentNode.insertBefore(a, m) // 将 a 脚本插入到 m 脚本之前
})(window, document, 'script', 'http://***/***.js', 'ga');
// i s o g r
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
过程是:
创建了一个 <script> 元素,并异步加载 http://***/***.js;初始化了一个全局函数 ga;在 ga() 命令队列中添加了两条命令。
现在我们可以在这个外部 js 中使用 ga.q 这个对象中的数据了,示例:
;(function () {
console.log(ga.q);
})(window);
简单补充下,async 是 HTML5 属性,使支持异步加载 JS 文件;defer 只支持 IE,作用类似。
测试异步只需要将 js 文件换成服务端页面,并人为设置 sleep 时间即可,阻塞式调用的话会在加载 js 时暂停后续页面的渲染。
WinForms 中嵌入 WebBrowser 默认是以 IE7 的兼容性视图渲染的,只要在网页的 <head /> 标签里加上:
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
就能以安装的最新内核渲染,这样就能用到 HTML5 的新功能啦!
http://npoi.codeplex.com/documentation
免费,开源,无需安装 Office,功能强大,兼容性好,使用方便,可以在 Visual Studio 的 NuGet 管理器中直接搜索安装。
导出 Excel 简单示例:
HSSFWorkbook book = new HSSFWorkbook();
ISheet sheet = book.CreateSheet("工作表1");
IRow r0 = sheet.CreateRow(0);
r0.CreateCell(0).SetCellValue("行1列1");
r0.CreateCell(1).SetCellValue("行1列2");
IRow r1 = sheet.CreateRow(1);
r1.CreateCell(0).SetCellValue("行2列1");
r1.CreateCell(2).SetCellValue("行2列3");
MemoryStream ms = new MemoryStream();
book.Write(ms);
Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}.xls", "文件名"));
Response.BinaryWrite(ms.ToArray());
Response.End();
book = null;
ms.Close();
ms.Dispose();
字体相关:
ICellStyle style = book.CreateCellStyle();
IFont font = book.CreateFont();
font.FontHeightInPoints = 20; // 字体大小
font.Color = HSSFColor.White.Index; // 字体颜色
style.SetFont(font);
style.FillForegroundColor = HSSFColor.Red.Index; // 背景色
style.FillPattern = FillPattern.SolidForeground;
cell.CellStyle = style;
合并单元格:
CellRangeAddress cra = new CellRangeAddress(r - 1, r - 1, c - 1, c);
sheet.AddMergedRegion(cra);
宽度自适应:
for (int i = 1; i < c; i++) {
sheet.AutoSizeColumn(i);
}
函数:
cell.SetCellFormula("SUM(B2:B4)");
顺便提一句,ICellStyle 和 IFont 最好一种样式一个变量先定义好再用,不要在循环里疯狂地 Create,否则超出数量(512个)会导致样式失效。
其它参考:http://www.ez2o.com/Blog/Post/csharp-Excel-NPOI-Font-Style