65.9K
CodeProject 正在变化。 阅读更多。
Home

LINQ to FQL (Facebook 查询语言)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (24投票s)

2009年3月9日

Ms-PL

8分钟阅读

viewsIcon

189983

downloadIcon

2474

一个支持类型化查询Facebook的库

LinqToFqlAddon/LinqToFql_logo.png

Facebook 开发工具包 LINQ to FQL 插件

前言

LINQ to FQL 是一个开源项目。源代码、二进制文件和示例可在 CodePlex 上找到。此库扩展了 Facebook 开发工具包

引言

此库使开发人员能够使用 LINQ(.NET 语言集成查询)与 Facebook 进行交互,而不是使用基于字符串的 FQL 查询。使用此库的主要好处是:

  • 类型安全:查询现在是类型的,其语法在编译期间进行验证。
  • 在 Visual Studio 中撰写查询时,自动完成功能现在可以正常工作。
  • 使用 Facebook / 匿名对象作为查询结果。

示例:以下示例代码检索所有好友的姓名和图片。

var db = new FacebookDataContext();
var friendIDs = from friend in db.friend_info where friend.uid1 == 
					db.uid select friend.uid2;
var friendDetails = from user in db.user where friendIDs.Contains(user.uid) 
			select new { Name = user.name, Picture = user.pic_small };

背景

虽然 LINQ 基础结构是可扩展的,但 LINQ to SQL(以前称为 DLINQ)基础结构则不然。其实现是内部的,并且仅支持 SQL Server。为了原生支持 FQL,需要从头开始模仿 LINQ to SQL 基础结构,具体如下:

  • FqlDataContext 表示支持 FQL 的数据源,并由 FqlTable 实例组成。
  • FqlTable 表示模型中的一个表,并作为 LINQ 查询的目标。
  • FqlDataQuery 表示在 FqlTable 上执行的 LINQ 查询。
  • FqlProvider 管理查询的转换和执行。
  • FqlQueryBuilder 将 LINQ 表达式转换为 FQL 字符串。
  • FacebookDataContext 派生自 FqlDataContext,并公开 Facebook 开发工具包模型作为表。

LinqToFql_diagram.png - Click to enlarge image

LINQ to FQL 查询的流程如下:

  1. 使用 LINQ 查询表(在 FqlTable.CreateQuery 中)。
  2. 分析 LINQ 表达式并将其转换为有效的 FQL 文本(在 FqlQueryBuilder.BuildQuery 中)。
  3. 通过 Facebook API 发送 FQL 文本(在 API.linq.query 中)。
  4. 返回 XML 结果,并将其反序列化回适当的对象(在 FqlQueryResultEnumerator.GetEnumerator 中)。

LINQ 到 FQL 的转换

LINQ 到 FQL 的转换通过 FqlQueryBuilder 类完成。此类接收表达式树,即 System.Linq.Expressions.Expression 的实例,并递归地迭代其子表达式。在迭代过程中,每个子表达式都根据其表达式数据和构建器的当前状态进行标识并转换为 FQL 文本。例如:

  • 查询子句(SELECTFROMWHEREORDERBY 等...)通过指向已知 LINQ 扩展方法的 MethodCall 表达式进行标识,例如,SELECT 子句应匹配 System.Linq.Queryable.Select 方法。
  • 当其成员类型实现 IFqlTable 接口时,表通过 MemberExpressions 进行标识。
  • 当其成员具有适当的自定义属性时,列通过 MemberExpressions 进行标识。
  • 当其成员类型实现 IFqlDataQuery 接口时,子查询通过 MemberExpressions 进行标识。

与 LINQ 集成

几个类和接口用于与 LINQ 集成。

  • IEnumerableIEnumerable<T>IEnumeratorIEnumerator<T> 用于返回物理可迭代结果。
  • IQueryableIQueryable<T> 用于创建对应用于其的 LINQ 查询具有更多控制权的类。
  • IQueryProvider 用于重写和执行查询。
  • System.Linq.Expressions 命名空间用作 LINQ 查询的基本模型。

该库中作为处理 LINQ 查询目标的类是 FqlTable<T> 类,它实现了 IQueryableIQueryProvider 接口。

public class FqlTable<T> : IQueryable, IQueryable<T>, IQueryProvider
{
  //IQueryable
  public IQueryProvider Provider
  {
    get { return this; }
  }
 
  //IQueryProvider
  public IQueryable<TResult> CreateQuery<TResult>(Expression expression)
  {
    return new FqlDataQuery<TResult>(this.context, expression, typeof(T));
  }
}

运行示例

此示例可在 在线 获取,只需点击 **运行** 按钮即可运行示例,或点击任意源文件以查看或编辑它们。

要在本地运行示例,请按照以下步骤操作:

  • 在 Visual Studio.NET 2008 中打开 SampleQuery.sln 文件。
  • 当提示为应用程序在 https:///SimpleQuery 创建虚拟目录时,请单击“是”。

您可以运行该应用程序,请注意,它将使用预定义的通用 Facebook 应用程序(由 CodeRun 提供),该应用程序会将 Facebook 重定向到您的本地示例。要使用您自己的应用程序,请继续执行以下步骤:

  • 在您的 Facebook 帐户中转到 **开发者应用程序**。
  • 点击“**设置新应用程序**”。
  • 给您的应用程序命名为 SimpleQuery
  • 将回调 URL 设置为:https:///SimpleQuery/facebookcallback.ashx
  • 在画布选项卡中,将 **渲染** 方法设置为 IFrame
  • 点击“保存更改”。
  • 在下一页上,将 API 密钥、应用程序密钥和应用程序 ID 复制并粘贴到示例项目的 web.config 文件中。
<appSettings>
	<add key="Facebook.Linq.ApplicationID" value="xxxxxxxx" />
 
	<add key="Facebook.Linq.APIKey" value="xxxxxxxxxxxxxxxxxxxxxx" />
	<add key="Facebook.Linq.Secret" value="xxxxxxxxxxxxxxxxxxxxxx" />
</appSettings>

通过点击 **在 Visual Studio 中运行** 或 此处 来运行应用程序。

Using the Code

使用 LINQ 查询的主要入口点是 FacebookDataContext 类。此类应包含 Facebook 的所有表,并且每个表都可以使用 LINQ 进行查询。要使用它,请创建一个 FacebookDataContext 的新实例,并在其上的任何表属性上使用 LINQ。

var db = new FacebookDataContext();
var myUser = db.user.Where(t => t.uid==db.uid).FirstOrDefault();

还可以使用 facebook.API 类(位于 Facebook 开发工具包程序集中)指定要使用的精确 Facebook 连接。

var api = new API { ApplicationKey = "MyAppKey", 
	AuthToken = "MyAuthToken", SessionKey = "MySessionKey", Secret = "MySecret" };
var db = new FacebookDataContext(api);

示例 1:语法

有两种使用 LINQ 的语法:一种称为 LINQ 查询语法,另一种称为 LINQ 方法语法。LINQ 查询语法是 C# 3.0 语言的一部分的全新原生实现。它不可扩展,因此存在一些限制。好消息是,两种语法可以在同一个查询中混合使用并获得相同的结果。

var db = new FacebookDataContext();
//LINQ Query Syntax
var friendsIDs = from friend in db.friend_info where friend.uid1 == 
					db.uid select friend.uid2;
//LINQ Method Syntax (the same query)
var friendsIDs2 = db.friend_info.Where(t => t.uid1 == db.uid).Select(t => t.uid2);

示例 2:嵌套查询

FQL 支持每个查询只使用一个表,这意味着不支持表连接。另一方面,FQL 允许使用嵌套查询来使用多个表,LINQ to FQL 也是如此。将来,此库应通过将使用 join 子句的 LINQ 表达式转换为嵌套或多个 FQL 查询来弥补这一不足。

var db = new FacebookDataContext();
var friendIDs = from friend in db.friend_info where friend.uid1 == 
					db.uid select friend.uid2;
var friendDetails = from user in db.user where friendIDs.Contains(user.uid) select user;
//Or in a single line
var friendDetails2 = from user in db.user where 
	(from friend in db.friend_info where friend.uid1 == 
	db.uid select friend.uid2).Contains(user.uid) select user;

显示我.

示例 3:检索特定属性

使用 LINQ 检索特定属性是通过 select 子句完成的,这是查询优化中的一个重要部分,因为它最小化了从 Facebook 返回的数据。Select 子句通常需要您拥有另一个对象来存储选择性数据,但不用担心,匿名类型 使这项工作变得非常简单。匿名类型允许您隐式定义一个具有一组只读属性的新类。在此示例中,将创建一个匿名类型,其中包含两个属性:NamePicture,两者都将是 String 类型。

var db = new FacebookDataContext();
var friendIDs = from friend in db.friend_info where friend.uid1 == 
					db.uid select friend.uid2;
var friendDetails = from user in db.user where friendIDs.Contains(user.uid) 
		select new { Name = user.name, Picture = user.pic_small };

显示我.

示例 4:分页和排序

排序使用 orderby 子句(使用查询语法)或 OrderBy 方法(使用方法语法)完成。分页使用 SkipTake 方法完成,请注意,分页没有 LINQ 查询语法替代项。分页也是查询优化中的一个重要部分,因为它限制了从 Facebook 返回的行数。

var db = new FacebookDataContext();
var friendIDs = from friend in db.friend_info where friend.uid1 == 
					db.uid select friend.uid2;
var friendDetails = (from user in db.user where friendIDs.Contains(user.uid) 
	orderby user.name select new { Name = user.name, 
	Picture = user.pic_small }).Skip(4).Take(5);

显示我.

facebook.Web 命名空间

facebook.Web 命名空间包含一些有用的类,用于帮助集成 Facebook。但是,它们对于 LINQ to FQL 基础结构不是必需的。例如,当您使用 FacebookDataContext 空构造函数时,将使用上下文的 facebook.API 对象。可以通过 FacebookContext.Current 属性或 FacebookContext.Get(httpContext) 方法访问此上下文,其中包含所有相关的 Facebook 上下文信息,例如当前登录的用户和应用程序信息。FacebookDataContext 类使用的默认应用程序在您的 web.config 文件中定义。

<appSettings>
 <add key="Facebook.Linq.ApplicationID" value="xxxxxxxx" />
 <add key="Facebook.Linq.APIKey" value="xxxxxxxxxxxxxxxxxxxxxx" />
 
 <add key="Facebook.Linq.Secret" value="xxxxxxxxxxxxxxxxxxxxxx" />
</appSettings>

为了完全支持 FacebookContext,您还应该在 web.config 文件中注册 FacebookCallback 处理程序。FacebookCallback 处理程序会自动处理与 Facebook 的重定向和回调,它还会自动处理登录过程。

<system.web>
 <httpHandlers>
 <add verb="*" path="FacebookCallback.ashx" type="Facebook.Web.FacebookCallback, 
	Facebook.Linq, Version=1.0.0.0, Culture=neutral, 
	PublicKeyToken=null" validate="false"/>
 
 </httpHandlers>
</system.web>

显示我.

使用此技术,可以更轻松地验证用户是否已登录,如果未登录,则会将其重定向到 Facebook 登录页面。

if (FacebookContext.Current.TryAuthenticating(true))
{
 var db = new FacebookDataContext(); //in here the FacebookDataContext 
		// object will use the currently authenticated user connection info.
}

显示我.

自定义 Facebook 模型

虽然 FqlDataContext 是一个通用的实现,旨在与任何模型配合使用,但 FacebookDataContext 类派生自它,并实现了一个特定的 Facebook 模型。这使您可以灵活地创建自己的 Facebook 模型并使用自定义属性将其映射到 FQL。此库实际上支持与原生 LINQ to SQL 实现相同的自定义属性,即 TableAttributeColumnAttribute。例如,考虑这个自定义的、更友好的 Facebook 模型:

[Table(Name="album")]
public class Album
{
 [Column(Name="aid", IsPrimaryKey=true)]
 public long ID { get; set; }
 
 [Column(Name="cover_pid")]
 public long CoverPictureID {get;set;}
}
 
public class FacebookFriendlyDataContext : FqlDataContext
{
	public FqlTable<Album> Albums
	{
 get
 {
 return GetTable<Album>();
 }
 }
}

性能指南

LINQ to FQL 是一个强大的工具,应谨慎使用。请记住,您的应用程序不是与本地数据库通信,而是与远程服务通信。您的应用程序通过此管道接收的任何数据都将作为 XML 消息通过 Internet 传输。因此,尽可能只获取应用程序真正需要的数据非常重要。最常见的方法是:

  • 仅选择需要处理或显示的列。
  • 使用 LINQ to FQL 基础结构过滤查询,而不是在内存中过滤。
  • 使用分页 - 如果您不打算显示或处理整个查询结果,请不要检索所有结果。

关注点

有用链接

未来版本

  • 完全覆盖 Facebook 模型
  • 数据存储 API 支持(个人 Facebook 数据库)
  • 关联支持(userid=>user)
  • 实体缓存

历史

  • 2009 年 3 月 9 日:初始发布
  • 2009 年 3 月 10 日:更新源代码
  • 2009 年 5 月 13 日:更新文章
  • 2009 年 5 月 21 日:更新文章
© . All rights reserved.