我同意 micro-ORM 可以解决您的场景或给您一些好主意的 cmets。 Massive 读起来很有趣,因为它可以放在一个文件中。它使用框架的dynamic 功能来解决您的问题。 Dapper 面向映射方面。
另外,看看Data Access Application Block。虽然现在是开源的,但它最初是由 Microsoft 维护的。它是一个整体的企业应用程序框架,因此您不需要几个臃肿的依赖项。但是数据访问块有一些很好的原型来满足您的要求:使用泛型将IDataReader 结果集映射到 POCO。因此,您只需编写一次映射代码,您为每个表定义的唯一内容就是实际的 reader-to-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;
}
}
您可以进一步打破这一点,定义一个行映射器而不是一个行 set 映射器,因为对读取器的迭代也可以被抽象出来。