高级查询
本文介绍一些复杂查询的使用场景。
IN 查询
XmlCommand定义
<XmlCommand Name="getByIn">
<Parameters />
<CommandText><![CDATA[
select * from Customers where CustomerID in ( {customerIdList} )
]]></CommandText>
</XmlCommand>
注意上面使用了一个 占位参数 {customerIdList}
C#调用代码
public async Task<List<Customer>> GetByIn(int[] ids)
{
var args = new { customerIdList = ids };
return await dbContext.XmlCommand.Create("getByIn", args).ToListAsync<Customer>();
}
或者用 CPQuery 来实现
public async Task<List<Customer>> GetByIn2(int[] ids)
{
string sql = "select * from Customers where CustomerID in ( {customerIdList} )";
var args = new { customerIdList = ids };
return await dbContext.CPQuery.Create(sql, args).ToListAsync<Customer>();
}
小结
- IN查询需要在SQL语句中使用一个占位参数
- 调用时,参数用数组或者List
来赋值 - 参数类型范围:
- int[], List<int>
- long[], List<long>
- string[], List<string>
- Guid[], List<Guid>
动态条件查询
示例代码,请仔细阅读代码中的注释
public class ProductBLL : BaseBLL
{
/// <summary>
/// 演示动态条件查询(多字段的组合查询)
/// </summary>
/// <param name="product"></param>
/// <param name="pagingInfo"></param>
/// <returns></returns>
public async Task<List<Product>> Search(ProductSearchParam product, PagingInfo pagingInfo)
{
// 这里演示一种【动态查询】,也就是根据一定条件拼接查询
// 先创建一个CPQuery基础对象,它包含查询哪些表,用于后面追加查询条件
CPQuery query = dbContext.CPQuery.Create("select * from Products where (1=1)");
if( product.CategoryID > 0 )
//【数字参数】可以直接相加,会自动变成SQL参数
query = query + " and CategoryID = " + product.CategoryID;
if( product.UnitPrice > 0 )
// 【数字参数】可以直接相加,会自动变成SQL参数
query = query + " and UnitPrice > " + product.UnitPrice;
if( string.IsNullOrEmpty(product.Unit) == false )
// 【字符串参数】由于不能自动识别(到底是SQL的一部分,还是参数),所以需要强制类型转换
query = query + " and Unit = " + (QueryParameter)product.Unit;
if( string.IsNullOrEmpty(product.ProductName) == false )
// 【字符串参数】,也可以调用扩展方法,转成参数对象
query = query + " and ProductName like " + product.ProductName.AsQueryParameter();
// 添加排序部分
query = query + " order by ProductId";
// 执行查询,获取结果
return await query.ToPageListAsync<Product>(pagingInfo);
}
}
注意:
- CPQuery和各种数据类型 相加 ,这里不是简单的字符串拼接!
- CPQuery实现了运算符重载,上面那些 + 会做特殊处理,将后面的数据转成标准SQL参数
- string数据需要 显式转换或者调用AsQueryParameter() ,之后才能与CPQuery相加
- 非string类型可以直接与CPQuery相加
- IN查询支持的数据类型,与可以和CPQuery相加
嵌套查询
占位参数还有另一种用法是实现【嵌套查询】,这里的嵌套是指 CPQuery和XmlCommand之间的嵌套。
可参考以下示例:
/// <summary>
/// WHERE中包含占位参数。 CPQuery 嵌套 CPQuery
/// </summary>
/// <returns></returns>
public async Task<DataTable> DemoNestQuery()
{
// 定义一个基础的SQL查询,它包含一个【固定SQL参数】,以及二个【占位符参数】
// {orderFilter} , {productFilter} 就是二个【占位符参数】,它们的位置将被另一个CPQuery实例来替换
string sql = @"
SELECT od.*, p.ProductName, p.Unit, p.UnitPrice, c.CustomerName, os.SumMoney, os.OrderDate
FROM Orders as os inner join OrderDetails as od on os.orderId = od.orderId
inner join Customers as c on os.CustomerID = c.CustomerID
INNER JOIN Products as p ON od.ProductID = p.ProductID
WHERE {orderFilter} and os.OrderDate > @OrderDate and {productFilter} ";
// 获取CPQuery的调用参数,包括2个占位参数
var args = GetArgs();
// 执行最终的查询
return await dbContext.CPQuery.Create(sql, args).ToDataTableAsync();
}
请认真查看示例代码中的注释。GetArgs()的代码如下:
private object GetArgs()
{
// 以下参数变量应该从方法外部传入,为了简单,这里直接硬编码
int oid = 1;
decimal money = 500;
string name = "%原装%";
decimal price = 20;
// 构造第一个【占位符参数】,也是根据一系列条件,动态生成
CPQuery orderFilter = dbContext.CPQuery.Create("(1=1)");
if( oid > 0 )
orderFilter = orderFilter + " and os.OrderID > " + oid;
if( money > 0 )
orderFilter = orderFilter + " and os.SumMoney > " + money;
// 构造第二个【占位符参数】,也是根据一系列条件,动态生成
CPQuery productFilter = dbContext.CPQuery.Create("(2=2)");
if( string.IsNullOrEmpty(name) == false )
productFilter = productFilter + " and p.ProductName like " + name.AsQueryParameter();
if( price > 0 )
productFilter = productFilter + " and p.UnitPrice > " + price;
return new {
OrderDate = new DateTime(2010, 1, 30),
orderFilter, // 注意这个参数赋值,它用于替换 {orderFilter}
productFilter // 注意这个参数赋值,它用于替换 {productFilter}
};
}
如果使用XmlCommand,C#代码会简洁一些:
/// <summary>
/// WHERE中包含占位参数。 XmlCommand 嵌套 CPQuery
/// </summary>
/// <returns></returns>
public async Task<DataTable> DemoNestQuery2()
{
// 获取XmlCommand的调用参数,包括2个占位参数
var args = GetArgs();
// 与上例相同的结果,只是将SQL分离到 XmlCommand 中
return await dbContext.XmlCommand.Create("demoNest", args).ToDataTableAsync();
}