diff --git a/docs/设计方案.md b/docs/设计方案.md index 0046c3e..ff36640 100644 --- a/docs/设计方案.md +++ b/docs/设计方案.md @@ -289,7 +289,7 @@ flowchart TB - **SqlClient 仿冒**(`runtime/Sim.Data`):SqlConnection / SqlCommand / SqlDataReader / SqlDataAdapter / SqlCommandBuilder / SqlParameter,DataSet、DataTable、DataView 直接用 .NET 自带的。连接字符串只按 Initial Catalog 打开学生自己的同名库(服务器名、账号密码不检查,书上的长服务器名、"." 都能连上),库不存在时报 4060。 - **T-SQL 转写**:ScriptDom(SQL Server 2008 语法)解析后按白名单逐个节点转写成 SQLite 语句,不认识的语法报"平台暂不支持",生成的 SQL 里只有平台写出的关键字和 tsql_ 函数。表用 STRICT 模式保存,原始的 T-SQL 列类型记在元数据表里,读出时还原成 SQL Server 返回的 .NET 类型(int、DateTime、bool……);varchar(n) 超长、类型不对、NULL、重复主键都报和 SQL Server 一样的错误号和中文信息。`insert into 表 values (...)` 不写列名时跳过自增列(照书上写时值的顺序和列顺序不一致,数据会存进错的列,和真实情况一样);日期统一存成 yyyy-MM-dd HH:mm:ss,书上拼接的 `DateTime.Now.ToString()`(2024/1/16 9:05:03)在插入和 BETWEEN 比较时都转换;支持 TOP(含 UPDATE / DELETE TOP)、CONVERT 样式 120 等、year / getdate / dateadd / datediff、`+` 按类型连接或相加、参数化查询、@@IDENTITY、多条语句。SqlCommandBuilder 根据带中文别名的查询生成 UPDATE。 - **DataGridView**:绑定 DataView / DataTable / DataSet,自动生成列;在单元格里修改的值写回 DataTable,配合 SqlDataAdapter.Update 保存;当前行 ▶、新增行 *、选中行、CurrentRow.Cells[0].Value;类型转换失败时和 WinForms 一样触发 DataError。**DateTimePicker**:Long / Short / Time / Custom 格式与中文 Windows 一致,弹出浏览器的日期选择框。设计器工具箱加"数据表格""日期时间选择器"。 - - **数据库页面**(代替 SSMS,`/database`):对象资源管理器(库 → 表 → 列,右键新建数据库、新建表、设计、选择前 1000 行、编辑前 200 行、删除);查询窗口(F5 执行、选中部分只执行选中的、USE 切换库,结果网格和消息栏的格式与 SSMS 一致,每批最多 5 秒);编辑前 200 行(改单元格即 UPDATE、* 行新增、右键删除,没有主键的表按所有列的原值定位);表设计器(列名、类型、允许 Null、右键设主键、标识列,"查看 SQL 脚本"显示对应的 CREATE TABLE);"恢复实验初始数据"按实验的 `database.sql` 替换实验用到的库,其他库不动。这些操作都生成 T-SQL 交给常驻的 SQL 服务执行,和学生程序走同一套转写。 + - **数据库页面**(代替 SSMS,`/database`):对象资源管理器(只有库 → 表两层,比 SSMS 简单:“+ 新建库”“+ 新建表”,点表名编辑前 200 行,⋯ 和右键是同一个菜单:查询前 1000 行、设计表结构、删除;鼠标停在表名上显示列);查询窗口(F5 执行、选中部分只执行选中的、USE 切换库,结果网格和消息栏的格式与 SSMS 一致,每批最多 5 秒);编辑前 200 行(改单元格即 UPDATE、* 行新增、右键删除,没有主键的表按所有列的原值定位);表设计器(列名、类型、允许 Null、右键设主键、标识列,"查看 SQL 脚本"显示对应的 CREATE TABLE);"恢复实验初始数据"按实验的 `database.sql` 替换实验用到的库,其他库不动。这些操作都生成 T-SQL 交给常驻的 SQL 服务执行,和学生程序走同一套转写。 - **评分**:每个实验可以带 `database.sql`,评分时每个检查项用一份新建的实验库,不碰学生自己的数据;评分规则加"点 / 修改表格单元格""在日期时间选择器里选日期""表格里有 / 没有某行"。新增示例项目 6 任务 2、3(任务 1 在数据库页面上完成),共 15 个。 - 实测:用到数据库的学生程序比不用的多约 11 MB 内存(PSS 17 → 28 MB)。另外修正了平台上的时间格式:Linux 的中文区域数据是 09:05:03,改成和中文 Windows 一样的 9:05:03。 diff --git a/web/public/help-img/db.webp b/web/public/help-img/db.webp index 98fb254..7f5e795 100644 Binary files a/web/public/help-img/db.webp and b/web/public/help-img/db.webp differ diff --git a/web/src/database/ObjectExplorer.vue b/web/src/database/ObjectExplorer.vue index 557c288..d52f8f8 100644 --- a/web/src/database/ObjectExplorer.vue +++ b/web/src/database/ObjectExplorer.vue @@ -1,5 +1,5 @@ - 对象资源管理器 - - - - {{ expanded.has('root') ? '▾' : '▸' }}📁 数据库 + + 数据库 + ↻ + + 新建库 + + + + 还没有数据库。点上面的“+ 新建库”,或者在页面顶部“恢复实验初始数据”。 + + + + {{ collapsed.has(db.name) ? '▸' : '▾' }} + {{ db.name }} + {{ db.tables.length }} 张表 + ⋯ - - (还没有数据库:右键"数据库"新建,或在上方恢复实验初始数据) - - - {{ expanded.has(`db:${db.name}`) ? '▾' : '▸' }}🛢 {{ db.name }} - - - - - {{ expanded.has(`tables:${db.name}`) ? '▾' : '▸' }}📁 表 - - - (没有表) - - - {{ expanded.has(`table:${db.name}/${table.name}`) ? '▾' : '▸' }}▦ dbo.{{ table.name }} - - - - - {{ expanded.has(`columns:${db.name}/${table.name}`) ? '▾' : '▸' }}📁 列 - - - - {{ column.primaryKey ? '🔑' : '▫' }} {{ columnText(column) }} - - - - - - - - - - - - + + + + {{ table.name }} + ⋯ + + + 新建表 + + + + diff --git a/web/src/pages/DatabasePage.vue b/web/src/pages/DatabasePage.vue index 7b28e69..f26e4d5 100644 --- a/web/src/pages/DatabasePage.vue +++ b/web/src/pages/DatabasePage.vue @@ -76,9 +76,16 @@ async function onAction(action: ExplorerAction) { case 'design': open({ kind: 'design', title: `${action.database} - dbo.${action.table.name}`, database: action.database, table: action.table }) break - case 'editRows': + case 'editRows': { + // 点表名打开编辑数据;这张表已经开着就切过去 + const opened = tabs.value.find((t) => t.kind === 'edit' && t.database === action.database && t.table.name === action.table.name) + if (opened) { + active.value = opened.key + break + } open({ kind: 'edit', title: `${action.database} - dbo.${action.table.name}`, database: action.database, table: action.table }) break + } case 'selectRows': { // 和 SSMS 生成的语句格式一样 const columns = action.table.columns.map((c) => quoteName(c.name)).join('\n ,') @@ -177,7 +184,6 @@ onMounted(refresh) ← 返回实验 数据库 新建查询 - 新建数据库 恢复实验初始数据 {{ currentUser?.name }}的数据库(只有自己能看到) @@ -200,7 +206,7 @@ onMounted(refresh) - 右键左边的"数据库"新建数据库;右键表可以编辑数据、设计表结构。 + 左边是你的数据库:点“+ 新建库”“+ 新建表”建库建表,点表名编辑表里的数据,表右边的 ⋯ 里还能查询、设计表结构、删除。 也可以点"新建查询",用 SQL 语句建库、建表、增删改查。 运行要用数据库的实验(教材项目 6 的任务 2、3,项目 8)时,平台会自动建好需要的库;把实验库恢复成初始数据,点"恢复实验初始数据"。 diff --git a/web/src/pages/HelpPage.vue b/web/src/pages/HelpPage.vue index 1d4662a..5ccd62b 100644 --- a/web/src/pages/HelpPage.vue +++ b/web/src/pages/HelpPage.vue @@ -141,14 +141,14 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey)) 7. 数据库(项目 6、8) - 点右上角的数据库(在新标签页打开),代替书上的 SSMS:右键新建数据库、新建表,新建查询写 SQL(输入时会提示关键字、表名和列名,写"表名."或"别名."列出这张表的列),按 F5 执行。 + 点右上角的数据库(在新标签页打开),代替书上的 SSMS:左边点“+ 新建库”“+ 新建表”,点表名编辑表里的数据,表右边的 ⋯(或右键)里能查询、设计表结构、删除;新建查询写 SQL(输入时会提示关键字、表名和列名,写"表名."或"别名."列出这张表的列),按 F5 执行。 每个人有自己的一套数据库,只有自己能看到,一直保留。程序里的连接字符串只看数据库名,服务器名、账号密码照书上写就行。 数据弄乱了:点恢复实验初始数据,选实验(默认是刚才做的实验),把这个实验用到的库换回初始数据(其他库不动)。 点← 返回实验回到刚才做的实验。 - 数据库页面:左边是对象资源管理器,右边写 SQL、按 F5 执行,下面是结果 + 数据库页面:左边是你的库和表(点表名编辑数据),右边写 SQL、按 F5 执行,下面是结果
还没有数据库。点上面的“+ 新建库”,或者在页面顶部“恢复实验初始数据”。
右键左边的"数据库"新建数据库;右键表可以编辑数据、设计表结构。
左边是你的数据库:点“+ 新建库”“+ 新建表”建库建表,点表名编辑表里的数据,表右边的 ⋯ 里还能查询、设计表结构、删除。
也可以点"新建查询",用 SQL 语句建库、建表、增删改查。
运行要用数据库的实验(教材项目 6 的任务 2、3,项目 8)时,平台会自动建好需要的库;把实验库恢复成初始数据,点"恢复实验初始数据"。