使用 lambda 表达式查询
自从 LINQ
出现以后,越来越多的框架采用了 lambda
表达式进行查询,因而出来了之如 linq to sql
、linq to entities
、linq to xml
等等很多新名词。其核心离不开对 lambda
表达式的解析并执行查询,最终返回结果。
与 Entity Framework
或其他框架一样,在 Fireasy 中可以使用 lambda
表达式查询语法。Fireasy 的 lambda
解析引擎支持大部份复杂的语法,但个别语法受可能受数据库的支持影响。
下面的示例是对 LINQ
查询的支持:
[TestMethod]
public void TestQuery()
{
using (var db = new DbContext())
{
var stuff = (
from o in db.Orders
where o.Customers.Country == "USA"
where o.Customers.City != "Seattle"
select new { CustomerName = o.Customers.CustomerName, OrderDate = o.OrderDate }
).ToList();
Assert.AreEqual(108, stuff.Count);
}
}
同样也是支持比较流行的 Fluent
方式(点方法):
[TestMethod]
public void TestQuery()
{
using (var db = new DbContext())
{
var stuff = db.Orders
.Where(o => o.Customers.Country == "USA")
.Where(o => o.Customers.City != "Seattle")
.Select(o => new { CustomerName = o.Customers.CustomerName, OrderDate = o.OrderDate })
.ToList();
Assert.AreEqual(108, stuff.Count);
}
}
所支持的标准的 Fluent
方法有以下这些:
- Where
- Select / SelectMany
- First / FirstAsync
- FirstOrDefault / FirstOrDefaultAsync
- Last / LastAsync
- LastOrDefault / LastOrDefaultAsync
- Single / SingleAsync
- SingleOrDefault / SingleOrDefaultAsync
- Skip / Take
- GroupBy
- Join
- Orderby / OrderbyDescending
- Thenby / ThenbyDescending
- Any / All
- Sum / SumAsync
- Count / CountAsync
- Average / AverageAsync
- Min / MinAsync
- Max / MaxAsync
- ToListAsync
- ToArrayAsync
- ToDictionaryAsync
这些方法的使用就不在赘述了,可参考相关的技术文档,以下仅对一些特殊的用法进行举例说明。
1、关联查询
一旦实体间建立了关系,就可以使用关联查询,并且在返回时顺便将关联的实体或集合带回。如下所示:
[TestMethod]
public void TestReferenceQuery()
{
using (var db = new DbContext())
{
var list = db.Orders
.Where(s => s.OrderDetails.Count() > 0)
.Where(s => s.Customer.City == "kunming")
.Select(s => new { Order = s, Customer = s.Customer, Details = s.OrderDetails })
.ToList()
}
}
2、返回相关
Select 语法与 Entity Framework
不同这处在于,这里可以返回任意的对象类型,表达式中可以应用内部或外部的任意方法,而 Entity Framework
是不支持的。如下所示:
private class OrderResult
{
public string Date { get; set; }
public string RecorderLevel { get; set; }
public string Phone { get; set; }
public string FirstName { get; set; }
public string ShortDate { get; set; }
}
[TestMethod]
public void TestComplexSelect()
{
using (var db = new DbContext())
{
var func = new Func<string, string>(s => s.Substring(0, 1));
var list = db.OrderDetails
.Take(2)
.Select(s => new OrderResult
{
Date = s.Orders.OrderDate.Value.ToLongDateString(),
RecorderLevel = s.Products.ReorderLevel.GetDescription(),
Phone = s.Orders.Customers.Phone,
FirstName = func(s.Orders.Customers.CompanyName),
ShortDate = s.Orders.OrderDate.Value.ToString("G")
});
}
}
在此例中,成员绑定分别应用了成员方法 DateTime.ToLongDateString() 和 ToString("G")、扩展方法Enum.GetDescription()、委托进行绑定。
也可以直接将外部方法或委托应用于 Select 表达式。如下所示:
[TestMethod]
public void TestInvokeSelect()
{
using (var db = new DbContext())
{
var func = new Func<OrderDetails, object>(s => new { s.ProductID, s.OrderID });
var list = db.OrderDetails
.Take(2)
.Select(func);
}
}
3、分组相关
分组语法 GroupBy 除了支持 Sum、Max 等聚合函数外,还支持 string.Join 方法。如下所示:
[TestMethod]
public void TestGroupby()
{
using (var db = new DbContext())
{
var list = db.Orders.GroupBy(s => s.CustomerID,
(s, t) => new
{
CustomerID = s,
Count = t.Count(),
FreightAvg = t.Average(v => v.Freight),
ShipNames = string.Join(", ", t.Select(v => v.ShipName))
})
.ToList();
}
}
注意 string.Join 的用法,Select 暂时不能在其后使用其他的方法,比如 OrderBy、Distinct 等等。另外,SQLServer 2017 以下的版本是不支持此用法的。
如果分组紧跟后面使用 Where 表达式中有聚合函数产生的列,则会自动转换为 Having 表达式。如下所示:
[TestMethod]
public void TestGroupbyHaving()
{
using (var db = new DbContext())
{
var list = db.Orders.GroupBy(s => s.CustomerID,
(s, t) => new
{
CustomerID = s,
Count = t.Count(),
FreightAvg = t.Average(v => v.Freight)
})
.Where(s => s.Count > 0 && s.FreightAvg > 0)
.ToList();
}
}