實體 SQL (Entity SQL),它是一種新的 SQL 語言,其中加入了之前的 SQL 語言並不支持的基於概念的查詢功能。ESQL 擴展現有 SQL 語言的方式與 EDM 擴展數據庫中所使用的關系模型的方式十分類似。此外,ESQL 未綁定到任何特定於後台數據庫的語法,因此可一次性編寫查詢(和/或應用程序),無論針對的是哪個後台數據庫都無影響。
Entity SQL 是基於文本的、面向集合的、延後綁定的查詢語言,也受到了T-SQL的影響。可以使用Entity SQL 創建對EDM的查詢,Entity SQL 既可以通過Object Services components來執行,也可以通過Entity Client components 來執行。Entity SQL 設計的非常靈活,因此也變得有些復雜。本篇文章側重於不同的查詢技術,僅僅使用簡單的查詢,不包含復雜的條件、關聯和聚合公式。
本系列文章上一篇:
Entity Data Model (EDM) 深入分析, Part 1
1. 使用ObjectQuery<T> 查詢返回實體類型(Entity Type)集合
下面演示如何執行Entity SQL 查詢,返回實體類型的實例集合。
1) 首先創建Northwind ObjectContext 實例。
2) Entity SQL語句本身是字符串表達式,在大多數情況下,由SELECT-FROM 查詢語句組成。在SELECT語句中使用VALUE關鍵字來表示返回的實體是一條數據行。
3) 使用Object Services components 執行查詢。調用ObjectContext 的工廠方法CreateQuery<T>(),創建一個ObjectQuery 對象,該對象表示對存儲數據源的查詢,查詢表達式為Entity SQL 語句。
4) Entity Framework實體框架采用延遲裝載(Deferred loading)。因此只有在顯式需要數據時,才真正執行SQL語句。在這種情況下,在ForEach第一次迭代時,才執行查詢語句。
NorthwindEntities context = new NorthwindEntities();
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp";
var query = context.CreateQuery<Employee>(sql);
foreach (var emp in query)
Console.WriteLine("{0} {1} {2} {3}", emp.EmployeeID, emp.FirstName, emp.LastName, emp.Country);
除了使用工廠方法CreateQuery<T>外,也可以直接創建ObjectQuery對象實例,並傳入Object Context 參數,示例代碼如下:
NorthwindEntities context = new NorthwindEntities();
var sql = "NorthwindEntities.Employees";
ObjectQuery<Employee> query = new ObjectQuery<Employee>(sql, context);
foreach (var emp in query)
Console.WriteLine("{0} {1} {2} {3}", emp.EmployeeID, emp.FirstName, emp.LastName, emp.Country);
下面增加一個WHERE條件:
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.Country = 'USA'";
var query = context.CreateQuery<Employee>(sql);
2. 帶參數的ObjectQuery<T>查詢
參數變量是在Entity SQL外定義的,在查詢語句中需要以@符合作為前綴定義變量名。參數定義為ObjectParameter 對象,然後增加到ObjectQuery 實例中。
下面增加一個Country 變量:
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.Country = @country";
var query = context.CreateQuery<Employee>(sql);
query.Parameters.Add(new ObjectParameter("country", "USA"));
同樣以ObjectQuery 示例對象實現這一功能:
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.Country = @country";
ObjectQuery<Employee> query = new ObjectQuery<Employee>(sql, context);
query.Parameters.Add(new ObjectParameter("country", "USA"));
ObjectParameter對象也可以直接傳入CreateQuery<T>方法:
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.Country = @country";
var query = context.CreateQuery<Employee>(sql, new ObjectParameter("country", "USA"));
第三種方法的是使用Where 擴展方法,使用關鍵字it 指向當前的查詢語句:
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp";
var query = context.CreateQuery<Employee>(sql)
.Where("it.Country = @country", new ObjectParameter("country", "USA"));
3. ObjectQuery<T> 查詢返回基本類型(Primitive Type)
除了返回實體類型外,也可以返回基本類型集合,因此需要確保SELECT語句僅僅返回1個值,同時也需要在CreateQuery方法中指定需要返回的基本類型。
var sql = "SELECT VALUE emp.EmployeeID FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.Country = @country";
var query = context.CreateQuery<int>(sql, new ObjectParameter("Country", "USA"));
foreach (var id in query)
Console.WriteLine("{0}", id.ToString());
另一示例腳本:
var sql = "SELECT VALUE emp.Country FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.EmployeeID = @id";
var query = context.CreateQuery<string>(sql, new ObjectParameter("id", 1));
Console.WriteLine(query.First());
除了使用 Entity SQL外,你也能使用查詢構造(Query Builder)方法實現相同的效果。Entity SQL 提供了SelectValue 方法,可以提過隱式的行構造器,僅僅返回指定的列。
string country = context.Employees.SelectValue<string>("it.Country", new ObjectParameter("id", 1)).First();
Console.WriteLine(country);
4. ObjectQuery<T> 查詢返回匿名類型
也有可能需要調整數據,並使用ObjectQuery<T>查詢返回匿名類型。在CreateQuery 方法中,改變SELECT語句並使用DbDataRecord 類,DbDataReader類在.NET 1.0引入,它提供了對任何枚舉類型的數據綁定支持。
var sql = "SELECT emp.LastName, emp.FirstName " +
"FROM NorthwindEntities.Employees AS emp ";
var query = context.CreateQuery<DbDataRecord>(sql);
foreach (var emp in query)
Console.WriteLine("{0} {1}", emp[0], emp[1]);
另一示例代碼:
var sql = "SELECT emp.LastName AS FamilyName, emp.FirstName " +
"FROM NorthwindEntities.Employees AS emp ";
var query = context.CreateQuery<DbDataRecord>(sql);
foreach (var emp in query)
Console.WriteLine("{0} {1}", emp["FamilyName"], emp["FirstName"]);