通用的dapper QueryMultiple函数

时间:2014-09-19 12:15:26

标签: c# asp.net-mvc generics dapper

我正在为我的网络应用程序使用asp.net mvc,dapper和MySql存储过程。 到目前为止,对于每个页面我都有1-3个存储过程调用。 我最近发现我的主机只提供10个并行连接,所以我想将每个调用组合成一个。 我已经在数据库中创建了必要的存储过程,但我的问题是以通用的方式使用dapper来获取程序结果。

我想要的是制作一个通用函数: 1)存储过程名称。 2)存储过程返回的类型列表。对于每种类型,如果它是Single / ToList。 泛型函数应该生成一个变量列表,它是存储过程的结果。

dapper页面中的示例显示了如何进行非通用的QueryMultiple调用:

var sql = 
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";

using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
   var customer = multi.Read<Customer>().Single();
   var orders = multi.Read<Order>().ToList();
   var returns = multi.Read<Return>().ToList();
   ...
} 

基本上,我想要的是将Customer,Order,Return类型插入到一个字典中,该字典会将每个类型声明为Single或ToList,然后执行以下操作:

var result = new List<dynamic>();
var sql = 
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";

using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
   foreach(var item in dictionary)
   {
       if (item.Value.equals("Single"))
           result.Add(multi.Read<item.Key>().Single());
       else if (item.Value.equals("ToList"))
           result.Add(multi.Read<item.Key>().ToList());
   }
}
return result;

我的问题是,visual studio说:

The type or namespace name 'item' could not be found

指向'item':multi.Read()

我做错了什么? 有没有更好的方法来实现使用dapper的QueryMultiple的泛型函数?

2 个答案:

答案 0 :(得分:2)

虽然这是一个古老的话题,但认为它可能对其他人有所帮助。在这种情况下,您可以使用下面的代码使其工作。将Read函数中的类型作为参数传递。你可以返回动态。使用Expando对象可以动态生成属性。

我更喜欢创建像下面这样的对象,并将对象列表传递给函数,这将为您生成动态返回类型。

public class MapItem
{
    public Type Type { get; private set; }
    public DataRetriveTypeEnum DataRetriveType { get; private set; }
    public string PropertyName { get; private set; }

    public MapItem(Type type, DataRetriveTypeEnum dataRetriveType, string propertyName)
    {
        Type = type;
        DataRetriveType = dataRetriveType;
        PropertyName = propertyName;
    }
}

 //And then make a reusable function like below

public async Task<dynamic> ExecuteQueryMultipleAsync(IDbConnection con, string spName, object param = null,IEnumerable<MapItem> mapItems = null)
    {
        var data = new ExpandoObject();

        using (var multi = await con.QueryMultipleAsync(spName,param, commandType:CommandType.StoredProcedure))
        {
            if (mapItems == null) return data;

            foreach (var item in mapItems)
            {
                if (item.DataRetriveType == DataRetriveTypeEnum.FirstOrDefault)
                {
                    var singleItem = multi.Read(item.Type).FirstOrDefault();
                    ((IDictionary<string, object>) data).Add(item.PropertyName, singleItem);
                }

                if (item.DataRetriveType == DataRetriveTypeEnum.List)
                {
                    var listItem = multi.Read(item.Type).ToList();
                    ((IDictionary<string, object>)data).Add(item.PropertyName, listItem);
                }
            }

            return data;
        }
    }

以下如何调用上述方法:

var mapItems = new List<MapItem>()
        {
            new MapItem(typeof(YourObject1), DataRetriveTypeEnum.FirstOrDefault, "Object1"),
            new MapItem(typeof(YourObject2), DataRetriveTypeEnum.List, "Object2")
        };

        var response = await ExecuteQueryMultipleAsync(name, request, mapItems);

        var object1 = response.Result.Object1;
        var listOfObject2 = ((List<dynamic>)response.Result.Object2).Cast<YourObject2>();

希望这会有所帮助。

干杯

答案 1 :(得分:0)

我认为可以使用替代方法代替QueryMultiple()方法,您可以使用

IDbConnection.ExecuteReader() 
来自Dapper.SqlMapper

扩展方法,它返回IDataReader,您可以遍历它并通过reader.NextResult()获取结果集并将其映射到您的对象。