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

智能数据层

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.65/5 (10投票s)

2007 年 6 月 19 日

5分钟阅读

viewsIcon

45788

downloadIcon

1299

一篇关于与数据库通信并即时生成 SQL 查询的文章

Screenshot - intelligent_datalayer.jpg

引言

这个智能数据层可以与数据库通信,并动态生成 SQL 查询。智能数据层的真实名称是 CDataLayer 库。CDataLayer 是一个编程 SQL 生成库。智能数据层的基本思想是,在不使用 .NET ADO 对象(DataAdapters、DataCommandBuilders 等)或存储过程的情况下,从数据库中选择、更新、删除或插入数据。使用智能数据层的对象可以通过查看其结构和数据库中相应表的结构来更新自身。使用智能数据层构建项目可能是一项奇迹。另一方面,您应该记住,便利性需要性能。每次创建对象时,您都会向数据库服务器发送一个类似 SELECT TOP 1 * FROM Categories 的 SELECT 查询。此查询从表中提取列的结构。然后可以使用此信息生成 SQL 查询。CDatalayer 库可以与 Microsoft SQL Server 和 Microsoft Office Access 数据库一起使用。

Using the Code

要使用 CDataLayer,您应该将 CDataLayer.dll 添加为引用。或者,您可以直接将 CDataLayer 项目添加到您的解决方案中。对于演示项目,您需要 SQLServer 2000 Northwind 数据库样本。将 Products 表中的 ProductID 列名更改为 ProductsID。在 CObjectInfoColllection 类中,主键列会被检测到,并且不会包含在更新查询中。

// Primary Columns should not be updated. 
// In the update statements they generate errors.
// Detect Primary Columns by their names which have the 
// form of {TABLE_NAME}.ID
// Do not add primary columns into FieldValues collection.
if (iObjectInfo.Name == _memberName.Substring(
    _memberName.IndexOf(".")+1) + "ID")
continue;

数据库中的每个表都应该在代码中用两个类来表示。例如,如果您的数据库设计中有一个 Customer 表,您应该编写相应的 CustomersCustomersTable 类。每个数据库表都必须有一个主键。这个键用于从表中选择唯一数据。CustomersCustomersTable 分别派生自 CMappedRowCMappedTable 类。这两个类都有抽象成员。

public abstract string IdentityColumn {get;}
public abstract string ObjectName {get;}
public abstract DataBaseLanguage DBLanguage { get;}

因此,您应该在派生类中实现它们,如下所示:

// Overrides
public override string ObjectName
{
    get { return "Customers"; }
}
public override string IdentityColumn
{
    get { return "CustomerID"; }
}
public override DataBaseLanguage DBLanguage
{
    get { return CGlobal.DBLanguage; }
}

CDataLayer.DataBaseLanguage 枚举目前有两个成员:Turkish 和 USAEnglish。智能数据层需要此类信息才能在 SQL 查询中正确编写日期时间选择。ObjectName 是数据库中表的名称,IdentityColumn 是表中主键列的名称。在 CGlobal.cs 类中,填写相应的值。

#region Private Members
    private static SqlConnection _SqlConnection;
    private static StringBuilder _SqlConnectionString;
    private static string _serverAddress = "localhost";
    private static string _databaseName = "Northwind";
    private static string _userID = "sa";
    private static string _password = "1234";
#endregion

如果您想处理单个数据行,您应该创建 {TABLENAME} 类的对象。要处理数据表,请创建 {TABLENAMETable} 类的对象。智能数据层可以处理 SqlConnection 和 OleDbConnection 连接类型。在 CMappedRowCMappedTable 类的构造函数中,您会创建一个 CMappedRowFactoryCMappedTableFactory 类的对象。这两个类都派生自 CMappedBase 类。

Screenshot - cmappedbase.png

如您所见,这些类相当复杂。通过调用 GetQuery_{METHOD_NAME},您可以获得每个 select、insert、update 和 delete 操作的 SQL 查询语句。CMappedRowCMappedTable 具有以下成员:

Screenshot - cmappedrow.png Screenshot - cmappedtable.png

示例

使用智能数据层填充数据网格的代码非常简短。

ProductsTable _productsTable = new ProductsTable(CGlobal.MsSQLConnection);
grdProducts.DataSource = _productsTable.SelectFromTable(true);

如果您只需要 SQL 查询,可以调用:

_productssTable.GetQuery_SelectFromTable(true);

如果您有一系列主键 ID,则可以检索与之相关的记录。此外,您还可以使用指定的列列表和排序方向来选择数据并对其进行排序,如下所示:

_MarkTable.SelectFromTable(new List<string>(new string[] { "Name" }), 
    new List<string>(new string[] { "ASC" }))

您可以通过主键获取单条记录,方法如下:

Products _product = new Products(CGlobal.MsSQLConnection, productID); 
// Create a product object from the datarow with specified productID
ucProducts.txtCategoryID.Text = _product.CategoryID.ToString(); 
// Get the CategoryID of the product
ucProducts.txtProductName.Text = _product.ProductName; 
// Get the ProductName of the product
ucProducts.txtQuantityPerUnit.Text = _product.QuantityPerUnit; 
// Get the QuantityPerUnit of the product

选择不同的记录 - 例如,为了填充组合框 - 可以使用 {TABLENAMETable}.SelectDistinctFromTable() 方法。在更新记录时,智能数据层会查看对象的所有属性,然后编写相应的查询。

在插入新记录时,只有已填写的属性才会被添加到 SQL 脚本中。您可以使用演示项目进行测试。将新记录插入数据库后,将执行另一个 SQL 查询 Select @@IDENTITY;。我们使用它来立即获取最近添加记录的主键 ID 号。

您可以通过为对象的属性提供虚拟值来生成搜索查询。例如,您可以编写如下搜索例程:

private void SearchInTable()
{
    _productsLoading = true;
    _productsTable = new ProductsTable(CGlobal.MsSQLConnection);
    _productsTable.ProductName = txtProductNameSearch.Text.Trim();
    _productsTable.UnitPrice = 
        CUtility.ConvertToDecimal(txtUnitPrice.Text.Trim());
    grdProducts.DataSource = 
        _productsTable.SearchInTable(SqlSearchType.AND_LIKE);
    txtSQLQuery.Text = 
        _productsTable.GetQuery_SearchInTable(SqlSearchType.AND_LIKE);
    _productsLoading = false;
}

ProductName 搜索关键字“on”和 UnitPrice “10”相对应的 SQL 查询将是:

SELECT ProductName, SupplierID, CategoryID, 
    QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
ReorderLevel, Discontinued FROM Products WHERE 
(ProductName LIKE '%on%' OR ProductName IS NULL) AND (
    UnitPrice=10 OR UnitPrice IS NULL);

您可以通过指定 SqlSearchType 枚举参数,使用四种逻辑情况来操作您的搜索关键字。

SqlSearchType.AND_EXACT
SqlSearchType.AND_LIKE
SqlSearchType.OR_EXACT
SqlSearchType.OR_LIKE

要删除单条记录,请使用 {TABLENAME}.DeleteRow() 方法。可以通过 {TABLENAMETable}.DeleteFromTable({PrimaryID list}) 方法删除指定 ID 号的行,如下所示:

ArrayList _Ids = new ArrayList();
_Ids.AddRange(new int[] { 1, 2 });
_productsTable.DeleteFromTable(_Ids);

CDataLayer 中的 CUtility 类包含一些有用的函数和一些数据类型转换函数。Cocnstans.cs 类包含所有枚举。所有 SQL 查询都在 CSql 类中构建。您对 {TABLENAME}{TABLENAME}Table 对象的各种方法操作越多,您将越了解 CDataLayer 及其功能。

祝您在使用这个智能数据层时愉快!

未来

我可能不再继续开发这个智能数据层了。欢迎对我的类和演示项目进行任何好的改进。

注意

我希望了解我的库的使用情况。如果您将使用我的库,请给我发送一封告知邮件。我需要这些信息只是为了激励自己并获得统计知识。我的邮箱是:

yeniferhat Screenshot - at.jpg yahoo.com

历史

  • 2007 年 6 月 19 日 - 发布原始版本
  • 2007 年 8 月 7 日 - 更新了文章和下载内容
  • 2007 年 8 月 9 日 - 更新了文章的引言和描述部分
© . All rights reserved.