SQL 表工具包 (STT)






4.98/5 (14投票s)
SQL 表工具包是一个类库,提供了大量用于快速轻松处理 SQL 表的工具。
引言
SQL 表工具包
是一个类库,提供了大量用于快速轻松处理 SQL 表的工具。每个表都被定义为一个类,其结构可以与 SQL 数据库同步。每个表类都具有基本的功能和方法,这些功能和方法可以直接在表类中或在应用程序的其他位置进行扩展。STT 始终使用 DataGridView
来进行表的视觉呈现。
表 SQL 语句是自动生成的,但也可以使用自定义 SQL 语句。稍后会详细介绍。用于表过滤的 SQL 语句也是自动生成的,并具有用于操作的方法。
表的所有功能都在表的上下文菜单中。通过一些代码,可以将它们实现到窗体控件中。所有这些功能都可以受到限制,以便我们决定用户是否可以添加或删除行。基本功能包括:
- 使用过滤表单过滤表;
- 移除过滤器;
- 表排序;
- 添加、删除和复制行;
- 表刷新和组合框源刷新;
- 更改协议及其查看;
- 每个用户的自定义列顺序及其维护;
- 计算基本值,如总和和最大值。
- 报告功能,可将表导出到动态 RDLC 报告。然后可以将该报告导出为 Excel、PDF 或直接打印。
上图显示了一个 表
的 上下文菜单
。
对于更改协议,STT 包含一些集成的表用于用户和权限管理。通过这种用户管理,还集成了登录模块,允许在应用程序启动时进行用户验证。
背景
在大型应用程序中使用 SQL 数据库处理可能会很麻烦。随着应用程序变大,SQL 后端会越来越难以维护。哦,天哪,如果需要进行更改,比如我向表中添加一个列。那些处理该表但没有更新的代码会使用它吗?如果我在一个地方添加了一个新行,但 SQL 语句中没有这个列怎么办?
也许对于拥有编程计划和指南的大型团队来说,这是他们必须处理的事情。此外,许多工具、最佳实践等都有助于维护这一切。我搜索了所有我能想到的信息,但没有找到适合我需求的东西:简单快速地编程 SQL 数据操作。只是因为我公司里的编程工作是“一人秀”,更改、新功能、新表和报告都必须在最短的时间内完成。
因此,我大部分时间都在与生产数据库一起工作。是的,我知道。这简直是疯狂的,你疯了吗,这个人到底怎么了……但是(没有但是!好的,我明白了)。我知道风险,也发生过糟糕的事情。对我来说,这样工作比自己测试更有效率,并且可以通过数据库备份来修复错误。因此,我使用我的最终用户作为 beta 测试人员。我首先自己进行测试,寻找关键错误和类似问题,小错误就留给最终用户。但是,为了不偏离 STT 的主题,我们继续。
我不是一个接受过正规教育的程序员。我不确定我是否能将自己定义为程序员。一切都始于 Excel 的问题解决,然后是具有少量功能的 Access 数据库,再到需要真实代码和 C# 等真实编程语言的 SQL 数据库。所以我开始阅读 OOP 的书籍,并发现了我制作这个小工具所需的一切。现在,经过一年多的使用和评估,我决定与互联网社区分享它。如果有人能将其用于自己的应用程序,我将不胜感激。这个工具目前在两家中小公司运行着两个 ERP 系统,我很少听到有什么问题或错误。
如果有人发现我的方法或代码存在严重错误,请告诉我。我将非常感谢任何建议和批评。
STT 的基本组成部分
表基础
当然,STT 的主类是 Table。即使它是 Toolkit 的主要部分,它也是 DgvAdapter 的子类。DgvAdapter 包含将表绑定到 DataGridView 的所有功能。如果一个表没有绑定到 DataGridView,则 DgvAdapter 不会被使用。关于 DgvAdapter,我们将在后续文章中讨论。
一个表由列组成。Column 类存储表列的所有属性。Columns 类是 Table 中所有列的列表。
过滤器基础
表过滤器的主类是 Parameter。Parameter 是表过滤器的一部分。每个表都有一个 Dictionary 属性,其中存储了所有表过滤器参数。对于过滤器,我们使用 Dictionary 而不是 List,因为 Dictionary 更便于操作其内容。在过滤中,我们需要不断添加、操作和删除参数。如果使用 List,这会导致很多问题。因为我们希望直接从表中操作表过滤器,所以参数 Dictionary 是表的属性,而不是像 Columns 那样分离到自己的类中。也可以这样做,但我们不会从中受益。
连接基础
表的连接存储在名为 Connection 的 Table 属性中,带有 getter 和 setter。通过获取 Table Connection,它始终返回一个打开的连接,而不是连接字符串。通过设置该属性,表 SQLConnection 被保存到 id。
SQLConnectionAdapter 类用于初始化 SQL Connection 或打开它。Open Connection 方法会检查连接是否已关闭或损坏,并在需要时打开它。
DgvAdapter
如前所述,DgvAdapter 是 Table 类的父类。它的主要功能是处理将 Table 绑定到 DataGridView 所需的所有繁重工作以及与之相关的所有内容。DgvAdapter 就像 STT 代码与用户之间的一个接口,这样不仅我们可以通过代码操作表数据,用户也可以。稍后在演示应用程序中,我们将展示如何使用 STT 将表绑定到 DataGridView。
在将 Table 绑定到 DataGridView 时,DgvAdapter 会捕获 DataGridView 事件,以确保所有功能都能正常工作。这使我们能够对 DataGridView 进行 STT 中未实现的所有自定义更改。
同步
为了将表同步到 SQL 数据库,我们只使用一个名为 Synchronization 的类。要同步一个表,只需发送其中包含该表的程序集,然后一个方法将完成其余工作。它会识别程序集中的每个表,并尝试将其与数据库同步。重要的是要注意,该方法不会删除行、列、表或数据库。这是因为在生产数据库上工作期间出于安全原因。另一个原因是使用 STT 的应用程序可以异步更新。这允许一个用户使用一个版本,而另一个用户使用旧版本,即使它们具有不同的数据库结构。列和表的删除留给开发人员。有可用于此的方法,但我个人不会冒险。
使用代码
演示应用程序
创建表
为了避免冗长的解释说明某个功能如何工作或如何完成,我们制作了一个小型演示应用程序,展示了 STT
的一些基本功能。我们将一步一步地完成项目的创建。
- 创建一个新的 Windows 窗体应用程序
- 为 STT dll 文件设置引用
之后,我们就可以开始使用 STT 了。
现在让我们创建一个新类并称之为 Table1
。我们将类设为 public,以便可以从其他项目访问它。在该类中,我们创建一个初始化方法。在该方法中,我们可以定义表连接和用户权限。我倾向于将表连接存储在项目的默认设置字符串值中,我总是称之为 Connection
。我使用字符串值是因为它可以被操作,而 SQLConnection 设置则不能。让我们看看我们的第一个表类。
public Table1()
{
Connection = new System.Data.SqlClient.SqlConnection(Properties.Settings.Default.Connection);
AllowUserToAddRow = true;
AllowUserToDeleteRow = true;
AllowuserToCopyRow = true;
AllowUserToFilter = true;
}
现在我们有了 Table
,接下来我们将向其中添加 Columns
。
public override void AddColumnsToTable()
{
Columns.AddDefaultColumns(this);
Columns.AddTextBox(this, "TextColumn", "Text Col.");
Columns.AddFloatBox(this, "FloatColumns", "Float Col.");
Columns.AddDateBox(this, "DateColumn", "Date Col.");
}
为此,我们重写 Table
方法 ADDColumnsToTable
。方法中的第一行代码是将 STT 的默认列添加到表中。这些列是 ID
和 Deleted
。
ID
是表的标识符,也是 SQL 数据库表中的主键。Deleted
是一个存储布尔值的列,默认值为 false。它们用于标记表中被删除的行。这也意味着通过添加默认列,用户实际上无法删除 SQL 数据库表中的行。它们只是被一个我们将立即添加的表默认过滤器隐藏了。
public override void SetDefaultParameters()
{
base.SetDefaultParameters();
SetParameter("Deleted", false);
}
当表被过滤时,总是会调用 SetDefaultParameters
方法。这样,用户就无法移除该过滤器,从而只显示 Deleted=false
的行。
要创建一个表,这些就足够了。让我们看看整个表代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using STT;
namespace STTDemoProject
{
public class Table1: Table
{
public Table1()
{
Connection = new System.Data.SqlClient.SqlConnection(Properties.Settings.Default.Connection);
AllowUserToAddRow = true;
AllowUserToDeleteRow = true;
AllowuserToCopyRow = true;
AllowUserToFilter = true;
}
public override void AddColumnsToTable()
{
Columns.AddDefaultColumns(this);
Columns.AddTextBox(this, "TextColumn", "Text Col.");
Columns.AddFloatBox(this, "FloatColumns", "Float Col.");
Columns.AddDateBox(this, "DateColumn", "Date Col.");
}
public override void SetDefaultParameters()
{
base.SetDefaultParameters();
SetParameter("Deleted", false);
}
}
}
将表添加到窗体
要在窗体中使用该表,以便用户可以使用它,我们需要一个 Form
和一个 DataGridView
来绑定表。在我们的演示项目中,我们将使用默认的 Form1
。在其中,我们添加一个 DataGridView
并将其 Dock
属性设置为 Fill
,使其填充整个窗体。
在窗体代码中,只需两行代码即可将其绑定到 DataGridView。
我们需要初始化表。
Table1 tblTable1 = new Table1();
并且我们需要将其绑定到之前添加到窗体的 DataGridView。
tblTable1.BindTableToDataGridView(dataGridView1);
要使表正常工作,这些就足够了。让我们看看整个 Form1
代码。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace STTDemoProject
{
public partial class Form1 : Form
{
Table1 tblTable1 = new Table1();
public Form1()
{
InitializeComponent();
tblTable1.BindTableToDataGridView(dataGridView1);
}
}
}
初始化表
为了让演示应用程序工作,我们必须告诉表在启动时 同步。在此之前,我们还必须告诉表它应该使用哪个连接。这将在 Program
类中完成。为了不硬编码连接,我们可以使用 STT 的内置模块。它是一个窗体,允许我们输入和测试 SQL 连接。在下面的代码中,我们初始化该窗体并使用其结果来继续连接或退出应用程序。如果应用程序没问题,我们将将其保存到我们的设置值 Connection
中,并保存默认的 应用程序 设置。
SQLConnectionForm frmConnection = new SQLConnectionForm(Properties.Settings.Default.Connection);
frmConnection.ShowDialog();
if (frmConnection.DialogResult != DialogResult.OK)
return;
Properties.Settings.Default.Connection = frmConnection.ConnectionString;
Properties.Settings.Default.Save();
重要提示:如果 SQL 连接直接存储在表中或手动通过代码添加,则 MultipleActiveResults 必须设置为 true,并且最大池大小必须设置为一个较大的数字(我使用 300000)。
设置好连接后,我们需要初始化表同步。然而,这不仅是为了我们创建的表,也是为了 STT 的表,因为即使我们不使用它们,它们也需要工作。下面的代码完成了初始化。
Initialization.Start(Assembly.Load("STT"), Properties.Settings.Default.Connection);
Initialization.Start(Assembly.Load("STTDemoProject"), Properties.Settings.Default.Connection);
更新: 现在我们还可以更改 STT 使用的语言(目前只有 EN 和 GE)。默认是 EN。如果我们不设置语言,它将自动为 EN。但为了演示目的,我们仍然会设置 EN。
Language.SetLanguage(Languages.EN);
Program
类的整个代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using STT;
using System.Reflection;
namespace STTDemoProject
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SQLConnectionForm frmConnection = new SQLConnectionForm(Properties.Settings.Default.Connection);
frmConnection.ShowDialog();
if (frmConnection.DialogResult != DialogResult.OK)
return;
Properties.Settings.Default.Connection = frmConnection.ConnectionString;
Properties.Settings.Default.Save();
Initialization.Start(Assembly.Load("STT"), Properties.Settings.Default.Connection);
Initialization.Start(Assembly.Load("STTDemoProject"), Properties.Settings.Default.Connection);
Language.SetLanguage(Languages.EN);
Application.Run(new Form1());
}
}
}
现在我们的演示项目已经完成,可以启动了。
启动演示应用程序
应用程序启动时,我们会看到一个窗体,可以在其中设置我们的 SQL 连接。
输入一个有效的连接并测试后,按 OK 继续。之后,我们将在 Form1 中看到我们的表,如下图所示。
通过点击 New
我们可以添加新行,或点击 Delete
删除行。在向表中添加一些数据后,我们可以通过点击 Report
来尝试报告模块。
这将打开表的动态报告。
通过点击“Change protocol
”或 Ctrl+P,我们可以查看特定行的更改协议。由于我们没有使用登录模块,用户未设置。
当然,表的过滤功能也已集成,只需点击 Filtern 即可打开一个窗体,我们可以在其中添加和删除表的过滤器参数。
演示项目可以下载。下载链接在文章开头。
其他功能
除了主要的表操作、更改协议和动态报告之外,STT 库还包含:
- STT 窗体的语言可以更改。
- 用户登录和用户操作。关于该主题的文章:使用 STT 的登录模块
- 具有用户权限的 TreeView 菜单和 TabControl,并在 TabControl 中打开窗体。
- 用于自定义更新功能、设置和更新检查的更新模块。
- 用户权限。
- 表列设置。
- 使用 STT 将 ComboBox 和其他控件绑定到 DataGridView。
- TreeView 菜单的权限。
- 错误处理,包括错误日志和自动向管理员发送电子邮件通知(带监控截图)。
- 轻松过滤表,无需使用硬编码的 SQL 语句。
- DataGridView 中的任何更改都会自动保存到服务器 - 无需保存按钮。
它旨在创建中小型企业规模的 ERP 应用程序。为此,STT 允许:
- 应用程序可以按水平模块拆分 - 每个部门或业务部分都可以拥有自己的模块,可以单独开发。
- 应用程序可以按垂直模块拆分 - 表可以分离到 dll 文件中,允许我们引用 dll 而不是项目(避免循环引用)。
- 业务逻辑可以直接写入表中 - 如果我们将其与数据库 dll 文件结合,就不需要在不同的用户界面中重写逻辑。
限制
- 表结构 - 如前所述,表依赖于具有
ID
作为标识符和Deleted
列来定义已删除行。SQL 表数据的呈现不依赖于这两列,但操作依赖。通过使用此工具获得的优势,我可以接受这一点。 - 用户过滤 - 用户过滤器只有一维。用户无法创建类似
WHERE (User=@UserID AND Deleted=1) OR (User=@UserID2)
的过滤器。括号的区别很大。 - 代码中的过滤 - 使用代码过滤表仅限于两个维度。这意味着上述语句可以使用权限组 ID 来实现(更多内容将在其他文章中介绍),但更复杂的语句则无法实现。对于这种情况,可以使用自定义代码和自定义表绑定源,STT 支持这些。
- 德语 - 部分代码/枚举仍为德语。我将尽快翻译。由于我需要实现对两个 ERP 系统的更改,因此需要更多时间。
已知错误
- SQL 连接 - 如果您使用 STT 进行大量表操作(每秒数千次),SQL 连接池可能会满,从而导致应用程序崩溃。我通过将连接的最大池大小设置为 30000 来“解决”这个问题。此外,MultipleActiveResults 必须设置为 True!
关注点
由于 STT 在一篇文章中包含的功能太多,并且为了使第一篇文章简短清晰,其他功能将在单独的文章中讨论,届时我可以进行更详细的介绍。
历史
2015 年 3 月 12 日 - 首次发布。
2015 年 3 月 17 日 - STT 添加了多语言支持。
2015 年 3 月 19 日 - 添加了关于登录模块的参考文章。
2015 年 3 月 25 日 - 添加了关于控件绑定和TreeView 菜单的文章的参考。