C#关系数据库






2.62/5 (59投票s)
2004年12月28日
5分钟阅读

86446

1750
本文介绍如何使用 C# 编写关系型数据库。
引言
ASP.NET 有其用于显示关系型数据库的“钻取”技术。我想介绍一种使用父/子多文档界面来显示关系型数据库的新思路。这比“钻取”有几个优点,因为如果需要,可以有几个子 MDI 文档,并且这些文档可以包含任意数量的信息,因为文档的大小可以调整到全屏。我们不像在“钻取”技术中那样,仅限于展开一条折叠的文本行。
这是父 MDI
这是子 MDI
ListBox 支持双击拆分字符串的功能。
我们将使用此方法添加另一个功能。我们将编辑记录,并在与父文档相同的页面上进行。我们只需双击记录,它就会将字符串拆分到页面顶部的文本框中。因为我使用 ListBox
查看记录,所以我可以使用“双击”事件来完成这项任务。在这里,在文本框中,我们可以根据需要编辑字段,然后按 F1,我们的更改就会被记录下来。
在大多数实际应用中,我们可能会将其编写为外部数据应用程序。在此示例中,为了简单起见,我“硬编码”了所有数据,这在教科书示例中很常见。
示例代码
拆分字符串
这是允许我们双击记录,并将字符串拆分到文本框中的代码的简短示例,以便我们可以进行编辑更改。我大量使用了子字符串和 Trim
。Trim
方法是必需的,用于删除字段末尾的空格。在进行编辑更改时,如果不对这些空格进行删除,它们就会堆积起来,然后损坏其余字段。然后我调用可重用的函数 ChangeText
。此用户定义的函数按值传递子字符串。在其他程序中,我根据具体情况使用了 String.Split
或 Regex.Split
。
多年前,我们用逗号分隔字段,然后使用 Regex.Split
可以很容易地按逗号拆分字段。如果您使用此类按空格分隔字段,并且字段之间有几个空格,那么 Regex.Split
将在每次出现空格时拆分。此类可能更难控制。我将根据您打算使用的类来设计您的数据。
关系型数据库
我创建了一个外部 .ocx 文件,并将 ListBox.SelectedIndex
写入该文件。这就是我将该信息传递给我的子 MDI 文档的方式。当子文档打开时,它会读取该外部文件,并从字符串数组中选择正确的索引。此索引被传递给一个字符串变量,然后解析回一个整数变量,我们以前在非托管代码的世界中称之为“装箱”。那时“西部”仍然狂野而未经驯服。我们必须调用“Marshal”来完成此操作。呵呵……这是与父文档中选定的记录对应的索引。
父 MDI
private void Form1_Load(object sender, System.EventArgs e)
{
// instantiate dialog box for creating records
relDat = new frmRelationalDatabase(new MyDelegate(ShowSplash));
// Declare Arrays
string[] FName = {"Dave", "Lilly", "Bob",
"Sandra", "Dick", "Ted",
"Kathy", "Angela", "Nick",
"Juan"};
string[] LName = {"Brighton", "Tomlin", "TheFather",
"Murphy", "Holiday", "Heathrow",
"Auburn", "Thomas", "TheGreek",
"Valdez"};
string[] DOB = {"05/23/1956", "02/03/1957", "01/01/1967",
"02/02/1967", "08/09/1967", "04/05/1976",
"06/06/1956", "07/02/1945", "05/05/1923",
"07/01/1948"};
string[] SocSec = {"123-23-3456", "234-23-2345", "345-23-1234",
"456-23-2345", "567-34-5678", "567-23-4567",
"234-34-2345", "456-12-7897", "456-23-6543",
"654-43-6543"};
// Format String
string strFormatString = "";
strFormatString = "{0, -10}{1, -12}{2, -12}{3, -12}";
// Loop through arrays and load formatted string into listbox
for( int i = 0; i < FName.Length; i++ )
{
// Instantiate new Stringbuilder class
// When we instantiate instance of new class here the class is
// recreated and therefore the memory is erased. This is easier
// than using StringBuilder.Remove
StringBuilder sb = new StringBuilder();
sb.AppendFormat(strFormatString, FName[i], LName[i],
DOB[i], SocSec[i]);
lstSplitString.Items.Add( sb.ToString() );
}
}
private void lstSplitString_DoubleClick(object sender,
System.EventArgs e)
{
string strSplit = lstSplitString.SelectedItem.ToString();
intIndex = lstSplitString.SelectedIndex;
strSplit1 = strSplit.Substring(0, 9);
strSplit2 = strSplit.Substring(10, 11);
strSplit3 = strSplit.Substring(22, 11);
strSplit4 = strSplit.Substring(34, 12);
txtFName.Text = strSplit1.Trim();
txtLName.Text = strSplit2.Trim();
txtDOB.Text = strSplit3.Trim();
txtSocSec.Text = strSplit4.Trim();
}
private void txtFName_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if( e.KeyCode == Keys.F1)
{
ChangeText( strSplit1, strSplit2, strSplit3, strSplit4 );
}
}
public void ChangeText(string strSplit1, string strSplit2,
string strSplit3, string strSplit4 )
{
// Instantiate new StringBuilder.
// We'll do this locally
// so the Stringbuilder is cleared
// each time.
StringBuilder sd = new StringBuilder();
// Format String
string strFormat = "";
strFormat = "{0, -10}{1, -12}{2, -12}{3, -12}";
// Pass values from textBoxes to
// string variables
strSplit1 = txtFName.Text;
strSplit2 = txtLName.Text;
strSplit3 = txtDOB.Text;
strSplit4 = txtSocSec.Text;
// Rebuild StringBuilder Class, and replace old listBox item
// with new information
sd.AppendFormat(strFormat,
strSplit1.Trim(),
strSplit2.Trim(),
strSplit3.Trim(),
strSplit4.Trim());
lstSplitString.Items.RemoveAt(intIndex);
lstSplitString.Items.Insert(intIndex,
sd.ToString());
// Clear textBoxes
txtFName.Clear();
txtLName.Clear();
txtDOB.Clear();
txtSocSec.Clear();
// Deselects listbox item
lstSplitString.Refresh();
}
private void lstSplitString_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if( e.KeyCode == Keys.Return )
{
if( File.Exists( myFileName ) )
{
// don't do nothing
}
else
{
// Create File
try
{
// Create File
File.CreateText( myFileName );
MessageBox.Show("New support file has been\r\n" +
"created, so restart program.",
"Important", MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
Application.Exit();
}
catch( IOException )
{
Application.Exit();
}
}
}
}
private void lstSplitString_KeyUp(object sender, System.Windows.Forms.
KeyEventArgs e)
{
try
{
// Pass listBox Selected Index to variable
intIndex = lstSplitString.SelectedIndex;
// Instantiate StreamWriter
StreamWriter streamWriter = new StreamWriter( myFileName );
// Writes to external file
streamWriter.Write( intIndex.ToString() );
// Closes StreamWriter
streamWriter.Close();
}
catch( Exception g )
{
MessageBox.Show( g.ToString(), "Important",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
finally
{
// Show Relational database Form
relDat.Show();
}
}
protected void ShowSplash()
{
Show();
}
子 MDI
private void frmRelationalDatabase_Activated(object sender,
System.EventArgs e)
{
string[] Address = {"4506 N. Hampton Rd \r\nFort Worth, TX" +
"\r\n67895 \r\n\r\n",
"1809 S. Long Ave. \r\nDobson, MO" +
"\r\n76946 \r\n\r\n",
"23 NW 64th St. \r\nSeattle, WA" +
"\r\n98073 \r\n\r\n",
"1208 Midwife Ln. \r\nLos Angeles, CA" +
"\r\n45034 \r\n\r\n",
"1906 Angina Way \r\nTemecula, CA" +
"\r\n23786 \r\n\r\n",
"56 Humboldt St. \r\nOracle, FL" +
"\r\n97845 \r\n\r\n",
"3406 W. Harris Ln. \r\nMongrove, OH" +
"\r\n56483 \r\n\r\n",
"567 E. Lala Lane \r\nBurks, ME" +
"\r\n67895 \r\n\r\n",
"3459 S. ShineEmOn Circle \r\nPhoenix," +
"AZ\r\n86578 \r\n\r\n",
"1 Way \r\nWhite House, DC" +
"\r\n11011 \r\n\r\n"};
// Instantiate SreamReader
StreamReader stream = new StreamReader( myFileName );
// Read From external file
strIndex = stream.ReadToEnd();
//Close StreamWriter
stream.Close();
txtAddress.Text = Address[ Int32.Parse( strIndex )];
strIndex = "";
txtAddress.Refresh();
}
为什么我们不使用属性来获取和设置我们的数据?
有几种方法可以将数据传递给 Windows 窗体。对于 Visual Basic 属性,这需要一个全局变量,或者 C# 的访问器和修改器。全局变量仅在 C++ 中可用。事实上,直到 C++ .NET 2003,Windows 窗体才在该平台上可用。公共作用域不足以让 Windows 窗体看到其他 Windows 窗体中的变量。
人们使用委托,甚至控件将数据传递给 Windows 窗体。这是一个在教科书中很少讨论的主题。教科书作者喜欢使用控制台应用程序来展示他们的示例代码。
使用这种架构是否存在任何可预见的问题?
ListBox
控件必须能够包含(显示)我们所有的数据。这就是我们利用“双击”事件来拆分记录字符串的方式。我已经对 ListBox
控件进行了测试,最多可容纳 1,000 条记录。根据记录的大小以及控件处理的最大字节数,最大记录数会有所不同。如果我们想增加记录的大小怎么办?
我们可能只显示最后 1,000 条记录,并将其余记录存档,一次处理一条。我们可以使用子 MDI 文档来查看溢出记录。我已经使用了文本搜索,因此我们只查看我们想要查看的数据库部分。
这就是编程的挑战。我们被吸引到这个研究中,因为它使我们能够发挥创造力。这种特定的架构风格旨在供小型数据库用户使用,因为它不允许索引,并且我们可以显示的记录数量是有限的。我做了一个测试。我编写了一个 do 循环,将测试记录的 1,000 个副本写入控件,看看它能容纳多少条记录。我写入 1,000 条记录,然后 10,000 条记录,然后 100,000 条记录到 ListBox
控件。如果它能经受住这个测试,那么我就知道最大容量是多少。我认为文本框的最大大小约为 64,000 字节。ListBox
没有列出此最大大小,但可能略小于文本框的最大大小。当然,对于大型数据库,总有 SQL Server 2000。
摘要
这是一种简单而通用的关系型数据库处理方法,并且能够在用户友好的环境中编辑记录。我相信它比目前流行的“钻取”技术更通用。有兴趣构建可分发程序的开发人员可以使用 C# 或 Visual Basic 语言。目标计算机只需安装 dotnetfx.exe 可再发行版,然后安装 .msi(Microsoft Installer)文件即可运行此可分发自定义关系型数据库。操作系统必须是 Windows 98 SE 或更高版本。