繁体   English   中英

使用ADO.NET,泛型从不同的表中获取SQL数据

[英]Fetching SQL data from different tables with ADO.NET, Generics

我经常指出,在开发连接到MS SQL数据库以实现基本CRUD功能的应用程序时,我需要遍历返回的结果并填充与表设计匹配的特定数据类型的列表。

特定于.NET,我只需创建一个方法(例如GetAllObjA()),然后使用ADO.NET指定一个SqlCommand,该SqlCommand可以连接到存储的Proc,以从返回的SqlDataReader中获取数据。 然后,我将遍历返回的行,创建一个新对象,并将其添加到每个对象的列表中。

但是,如果我想获取其他数据类型的数据,则将方法GetAllObjB(),GetAllObjC()等重写,而列表的数据类型不同,这似乎完全是在重写代码。

我意识到泛型在这里有一个目的,可以在一种方法中指定数据类型,例如GetAll <T>()。 不幸的是,这仍然需要我定义要从中获取数据的表,并且仍然需要使列名与对象中的成员名匹配,但这并不能真正解决问题,因为应用程序代码无法解决问题。了解表格的设计方式。

这是泛型在这种情况下有用的程度吗? 由于我正在构建的应用程序规模很小,因此,如果可以手动编码解决方案,我不认为需要ORM。

我同意微型ORM可以解决您的情况或为您提供一些好主意的意见。 大量读起来很有趣,因为它适合一个文件。 它使用框架的dynamic功能来解决您的问题。 Dapper面向映射方面。

另外,看看“ 数据访问应用程序块” 尽管现在是开源的,但它最初是由Microsoft维护的。 它是一个整体企业应用程序框架,因此您不需要几个several肿的依赖项。 但是数据访问块具有一些很好的原型来满足您的要求:使用泛型将IDataReader结果集映射到POCO。 因此,您只需编写一次映射代码,并且每个表唯一定义的就是实际的读取器到poco属性映射。

有时表或其映射可能会有一些怪癖,因此您需要手工保留映射定义。 对于其他具有基本基元的简单表,Rob Connery的Massive演示的动态方法与通用行集映射器的结合使用可以使某些非常易于阅读和维护的代码成为可能。

免责声明:这不是对这种方法相对于EF优缺点的判断。 它只是在建议一种简单的非EF方法。

因此,您可能有一个小的库定义了一个接口:

public interface IResultSetMapper<TResult>
{
    Task<List<TResult>> MapSetAsync(IDataReader reader);
}

以及处理任何阅读器的通用ADO.Net帮助器类:

// a method with a class that manages the Command (_Command) and Connection objects 
public async Task<List<TOut>> ExecuteReaderAsync<TOut>(IResultSetMapper<TOut> resultsMapper)
{
    List<TOut> results = null;
    try
    {
        using(var connection = await _DbContext.CreateOpenedConnectionAsync())
        {
            _Command.Connection = connection;

            // execute the reader and iterate the results; when done, the connection is closed
            using(var reader = await _Command.ExecuteReaderAsync())
            {
                results = await resultsMapper.MapSetAsync(reader);
            }
        }
        return results;
    }
    catch(Exception cmdEx)
    {
        // handle or log exception...
        throw;
    }
}

因此,以上代码将是一个帮助程序库,只编写了一次。 然后,应用程序中的映射器可能看起来像;

internal class ProductReaderMap : IResultSetMapper<Product>
{
    public async Task<List<Product>> MapSetAsync(IDataReader reader)
    {
        List<Product> results = new List<Product>();
        using(reader)
        {
          results.Add(new Product
          {
            ProductId = r.GetInt32(0),
            ProductName = r.GetString(1),
            SupplierId = r.GetInt32(2),
            UnitsInStock = r.GetInt16(3)
          });
        }
    return results;
    }
}

您甚至可以进一步定义一个行映射器,而不是一个行映射器,因为读者的迭代也可以抽象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM