65.9K
CodeProject 正在变化。 阅读更多。
Home

C#关系数据库

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.62/5 (59投票s)

2004年12月28日

5分钟阅读

viewsIcon

86446

downloadIcon

1750

本文介绍如何使用 C# 编写关系型数据库。

引言

ASP.NET 有其用于显示关系型数据库的“钻取”技术。我想介绍一种使用父/子多文档界面来显示关系型数据库的新思路。这比“钻取”有几个优点,因为如果需要,可以有几个子 MDI 文档,并且这些文档可以包含任意数量的信息,因为文档的大小可以调整到全屏。我们不像在“钻取”技术中那样,仅限于展开一条折叠的文本行。

这是父 MDI

这是子 MDI

ListBox 支持双击拆分字符串的功能。

我们将使用此方法添加另一个功能。我们将编辑记录,并在与父文档相同的页面上进行。我们只需双击记录,它就会将字符串拆分到页面顶部的文本框中。因为我使用 ListBox 查看记录,所以我可以使用“双击”事件来完成这项任务。在这里,在文本框中,我们可以根据需要编辑字段,然后按 F1,我们的更改就会被记录下来。

在大多数实际应用中,我们可能会将其编写为外部数据应用程序。在此示例中,为了简单起见,我“硬编码”了所有数据,这在教科书示例中很常见。

示例代码

拆分字符串

这是允许我们双击记录,并将字符串拆分到文本框中的代码的简短示例,以便我们可以进行编辑更改。我大量使用了子字符串和 TrimTrim 方法是必需的,用于删除字段末尾的空格。在进行编辑更改时,如果不对这些空格进行删除,它们就会堆积起来,然后损坏其余字段。然后我调用可重用的函数 ChangeText。此用户定义的函数按值传递子字符串。在其他程序中,我根据具体情况使用了 String.SplitRegex.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 或更高版本。

© . All rights reserved.