http://www.cnblogs.com/Sunmoonfire/archive/2012/08/07/2625955.html
介绍
在本文中,我们将介绍以下高级开发领域中的内容:
•LINQ to SharePoint
•SPMetal
LINQ to SharePoint 是SharePoint 2010的一项新特性。 LINQ 本身是 Language Integrated Query 的意思,它是 .NET的一个组成部分。 LINQ的设计目标是使用相同的类型化查询语法来支持不同类型的数据源。到目前为止,它可以支持Objects, Datasets, SQL, Entities, XML等。
为什么我们需要 LINQ?
从前我们针对 List 的编程都是使用相应的栏名来访问。有了LINQ 之后,我们就使用类型化的方式访问列表了。换句话说,使用类似访问数据库的方式去访问列表项。
就像下面这样:
var result = from c in Citizen where c.Name == “John” select c; |
什么是SPMetal?
我们创建了一个包含自定义栏的自定义列表后,还需要创建一个实体模型(Entity Model)与之对应,这样才能用LINQ来访问它。 SPMetal.exe 就是一个帮助我们生成 Model 类的工具。尽管我们可以手工创建Model 类,但毕竟这属于枯燥单调的工作,并且很容易出错。 所以用SPMetal 才是生成model 类的王道。
活动
本文将包含以下活动:
1. Manager 列表创建
2. 实体创建
3. 使用LINQ读取
4. 插入实体
5. 更新实体
6. 删除实体
开始 LINQ 和SPMetal 的体验之旅
作为实验对象,我们创建了一个自定义列表,名为Manager. 添加如下的自定义栏和数据:
生成实体模型
现在,我们就可以为以上列表生成实体模型。使用这个文件夹下的 SPMetal.exe来生成模型类:
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\BIN
打开命令行,进到该文件夹:
运行如下命令:
SPMetal.exe /web:http: //你的站点 /code:SiteEntities.cs |
过一会儿我们就会生成出一个新文件。打开SiteEntities 文件,我们就可以看到其中包含的Manager 类。
创建应用程序
新建一个SharePoint > 2010 > 控制台应用程序 (目标框架 .NET 3.5 framework) 并将 SiteEntities.cs 文件添加到该项目。
添加如下程序集引用:
我们可以尝试以下操作: 通过LINQ to SharePoint读取,插入,更新,删除。
读取项
我们先试一下查询country 为USA 的managers :
using (SiteEntitiesDataContext ctx = new SiteEntitiesDataContext("http://moss.contoso.com/sites/Lab01")) { var result = ctx.Manager.Where(m => m.国家 == 国家.USA); foreach (Manager项目 manager in result) { Console.WriteLine(manager.名称); } }
注: 我们可以使用 LINQ 或 Lambda 表达式来进行查询。上面的例子中我们用的是Lambda。
运行该应用程序,我们可以看到如下的结果。
插入项
如果要在Manager 列表中插入数据,可以使用如下代码:
using (SiteEntitiesDataContext ctx = new SiteEntitiesDataContext( "http://moss.contoso.com/sites/Lab01" )) { Manager项目 manager = new Manager项目(); manager.名称 = "新的经理" ; manager.地址 = "新的地址" ; manager.国家 = 国家.China; ctx.Manager.InsertOnSubmit(manager); ctx.SubmitChanges(); } |
执行以上程序后,打开SharePoint 中的Manager 列表,可以看到如下结果:
更新项
如果要更新SharePoint 中的列表项,可以使用如下代码:
using (SiteEntitiesDataContext ctx = new SiteEntitiesDataContext( "http://moss.contoso.com/sites/Lab01" )) { Manager项目 manager = ctx.Manager.Where(m => string .IsNullOrEmpty(m.标题)).FirstOrDefault(); if (manager != null ) { manager.标题 = "新的标题" ; } ctx.SubmitChanges(); } |
我们可以在SharePoint 上看到更新后的实体:
删除项
如果要删除SharePoint 中的列表项,可以使用如下代码:
using (SiteEntitiesDataContext ctx = new SiteEntitiesDataContext( "http://moss.contoso.com/sites/Lab01" )) { Manager项目 manager = ctx.Manager.Where(m => m.标题.Length>3).FirstOrDefault(); if (manager != null ) { ctx.Manager.DeleteOnSubmit(manager); } ctx.SubmitChanges(); } |
我们可以看到在SharePoint 中的该项已被删除:
以上就是如何通过LINQ to SharePoint 实现增删改查。希望大家都可以掌握。
总结
本文中我们使用了 LINQ 和SPMetal 工具。这些都是在实际的编程场景中经常使用的工具。
参考资料
http://msdn.microsoft.com/en-us/library/ee535491.aspx
http://msdn.microsoft.com/en-us/library/ee538255.aspx
SharePoint 2010 – LINQ and SPMetal
如何使用创建时间,修改者等系统信息?
INQ to SharePoint是2010版的SharePoint的一个很好的新特性,用于对SharePoint服务器发起查询。不同于经典CAML的查询,它是通过一个强类型的实体模型和LINQ查询语法来查询列表数据。
SPMetal命令
正如上一篇文章中提到的那样,使用LINQ to SharePoint的第一步就是运行SPMetal工具来为已有的SharePoint站点创建实体模型。此工具位于14\ BIN。这里有一个如何使用它的示例:
SPMetal /web:http: //我们的SharePoint站点:端口 /code:SiteEntities.cs |
这个命令将在在14\ BIN下创建一个名为 Model.cs 的C#代码文件,其中包含了实体模型。将这个文件添加到我们的项目后,我们就可以使用LINQ to SharePoint来执行查询了。例如,可以使用如下的服务器端代码,输出“Manager”列表中标题长度至少为3个字符长所有列表项:
using (SiteEntitiesDataContext ctx = new SiteEntitiesDataContext("http://moss.contoso.com/sites/Lab01")) { StringBuilder output = new StringBuilder(); foreach (Manager项目 manager in ctx.Manager.Where(x => x.标题.Length >= 3)) { output.AppendLine(manager.名称); } Console.WriteLine(output.ToString()); }
丢失的栏
默认情况下,创建者,创建时间,修改者,修改时间这些栏不会被SPMetal自动创建。然而,该框架提供了对LINQ to SharePoint提供程序的扩展能力,可以扩展其中的对象——关系映射系统。换句话说,一旦我们告诉了LINQ to SharePoint如何从内容数据库中检索和更新这些栏,那么以后就可以很容易地使用这些栏了。
下面我们就动手扩展模型的基础实体类(“项目”类),新建一个C#代码文件(这里命名为“Item.cs更多关于ICustomMapping接口的介绍,可以查看这些MSDN文章:ICustomMapping成员和RefreshMode枚举。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.SharePoint.Linq; using Microsoft.SharePoint; namespace MossTest { public partial class Item : ICustomMapping { [CustomMapping(Columns = new String[] { "Modified", "Created", "Editor", "Author" })] public void MapFrom(object listItem) { SPListItem item = (SPListItem)listItem; this.Modified = (DateTime)item["Modified"]; this.Created = (DateTime)item["Created"]; this.CreatedBy = (string)item["Author"]; this.ModifiedBy = (string)item["Editor"]; } public void MapTo(object listItem) { SPListItem item = (SPListItem)listItem; item["Modified"] = this.Modified; item["Created"] = this.Created; item["Author"] = this.CreatedBy; item["Editor"] = this.ModifiedBy; } public void Resolve(RefreshMode mode, object originalListItem, object databaseObject) { SPListItem originalItem = (SPListItem)originalListItem; SPListItem databaseItem = (SPListItem)databaseObject; DateTime originalModifiedValue = (DateTime)originalItem["Modified"]; DateTime dbModifiedValue = (DateTime)databaseItem["Modified"]; DateTime originalCreatedValue = (DateTime)originalItem["Created"]; DateTime dbCreatedValue = (DateTime)databaseItem["Created"]; string originalCreatedByValue = (string)originalItem["Author"]; string dbCreatedByValue = (string)databaseItem["Author"]; string originalModifiedByValue = (string)originalItem["Editor"]; string dbModifiedByValue = (string)databaseItem["Editor"]; if (mode == RefreshMode.OverwriteCurrentValues) { this.Modified = dbModifiedValue; this.Created = dbCreatedValue; this.CreatedBy = dbCreatedByValue; this.ModifiedBy = dbModifiedByValue; } else if (mode == RefreshMode.KeepCurrentValues) { databaseItem["Modified"] = this.Modified; databaseItem["Created"] = this.Created; databaseItem["Author"] = this.CreatedBy; databaseItem["Editor"] = this.ModifiedBy; } else if (mode == RefreshMode.KeepChanges) { if (this.Modified != originalModifiedValue) { databaseItem["Modified"] = this.Modified; } else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue) { this.Modified = dbModifiedValue; } if (this.Created != originalCreatedValue) { databaseItem["Created"] = this.Created; } else if (this.Created == originalCreatedValue && this.Created != dbCreatedValue) { this.Created = dbCreatedValue; } if (this.CreatedBy != originalCreatedByValue) { databaseItem["Author"] = this.CreatedBy; } else if (this.CreatedBy == originalCreatedByValue && this.CreatedBy != dbCreatedByValue) { this.CreatedBy = dbCreatedByValue; } if (this.ModifiedBy != originalModifiedByValue) { databaseItem["Editor"] = this.ModifiedBy; } else if (this.ModifiedBy == originalModifiedByValue && this.ModifiedBy != dbModifiedByValue) { this.ModifiedBy = dbModifiedByValue; } } } public DateTime Modified { get; set; } public DateTime Created { get; set; } public string CreatedBy { get; set; } public string ModifiedBy { get; set; } } }
将这个文件添加到我们的项目后,在我们进行查询时可以使用创建者,创建时间,修改者,修改时间了:
StringBuilder output = new StringBuilder(); using (SiteEntitiesDataContext model = new SiteEntitiesDataContext("http://moss.contoso.com/sites/Lab01")) { string dateStr = ("2012/8/6 16:22").ToString(CultureInfo.InvariantCulture); DateTime convertedDate = DateTime.SpecifyKind(DateTime.Parse(dateStr), DateTimeKind.Utc); foreach (Manager项目 manager in model.Manager.Where(x => x.Created > convertedDate)) { output.AppendLine(manager.标题 + " " + manager.名称); } } Console.WriteLine(output.ToString());
还是用原来的Manager列表,在当前视图中增加显示“创建时间”一栏:
以上的代码查询所有创建时间晚于16:22的列表项。结果如下:
需要注意的是,作者和修改者这两个栏是User类型的。直接输出这些字符串的话可能会含有很多你不需要的信息。解析这钟字符串的一个简单方法是创建一个SPFieldUserValue,用当前的SPWeb和这个字符串作为参数。然后,我们可以从SPFieldUserValue.User中提取出实际需要的SPUser信息。
比如:
using(SPSite site=new SPSite("http://moss.contoso.com/sites/Lab01")) { using (SPWeb web = site.OpenWeb()) { using (SiteEntitiesDataContext ctx = new SiteEntitiesDataContext("http://moss.contoso.com/sites/Lab01")) { var result = ctx.Manager.Where(m => m.国家 == 国家.USA); foreach (Manager项目 manager in result) { SPFieldUserValue t = new SPFieldUserValue(web, manager.CreatedBy); Console.WriteLine(manager.标题 + " " + manager.名称 + " - " + t.User.Name + " - " + manager.Modified.ToShortDateString()); } } } }
输出结果为:
希望此代码对你有帮助,Enjoy SharePoint!
Linq to SharePoint与权限提升
SharePoint 2010支持Linq to SharePoint,让程序员可以使用Linq语法直接访问SharePoint 2010网站中的数据。但是在默认情况下,Linq to SharePoint不支持权限提升,也就是说,如果在代码中尝试通过SPSecurity.RunWithElevatedPrivileges()方 法来提升执行权限,你可能会发现,代码并不会如你所愿的以系统帐户的身份,访问SharePoint网站的数据。
下面是一段典型的权限提升的代码,在匿名委托方法中,首先构造了新的SPSite和SPWeb对象,然后使用Linq to SharePoint查询了一个列表中所有列表项的标题。虽然看起来Linq to SharePoint好像会被提升它执行的权限,但实际情况并非如此。在下面的代码中,中间的Linq to SharePoint代码并不会受到外面调用SPSecurity.RunWithElevatedPrivileges()方法的影响。
private IEnumerable<String> GetAllHardwareNames()
{
var currentWebUrl = SPContext.Current.Web.Url;
List<String> result = null;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (var site = new SPSite(currentWebUrl))
{
using (var web = site.OpenWeb())
{
using (var ctx = new ContosoDataContext(currentWebUrl))
{
var names = from h in ctx.硬件资产跟踪
select h.标题;
result = names.ToList();
}
}
}
});
return result;
}
如果希望Linq to SharePoint代码能够提升它的执行权限,在使用Linq to SharePoint之前,需要做一个比较trick的事情,那就是将当前HttpContext对象设置为null。下面的代码中,使用粗体标识了这些特殊的代码。
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (var site = new SPSite(currentWebUrl))
{
using (var web = site.OpenWeb())
{
var httpContext = HttpContext.Current;
HttpContext.Current = null;
using (var ctx = new ContosoDataContext(currentWebUrl))
{
var names = from h in ctx.硬件资产跟踪
select h.标题;
result = names.ToList();
}
HttpContext.Current = httpContext;
}
}
});
只所以要使用这个技巧,是因为在Linq to SharePoint的实现中,使用了一个名为 Microsoft.SharePoint.Linq.Provider.SPServerDataConnection的类,来真正连接到 SharePoint网站。在这个类的构造函数中,有类似这样的代码:
if (SPContext.Current != null)
{
this.defaultSite = SPContext.Current.Site;
this.defaultWeb = (SPContext.Current.Web.Url == url) ? SPContext.Current.Web : this.defaultSite.OpenWeb(new Uri(url).PathAndQuery);
}
else
{
this.defaultSite = new SPSite(url);
this.defaultWeb = this.defaultSite.OpenWeb(new Uri(url).PathAndQuery);
}
为了提高性能,它会优先重用SPContext对象中所缓存的SPWeb和SPSite对象。这个行为虽然可以提高代码的运行效率,但是却会导致权限提升的失效,因为提升了权限的代码必须使用一个新构造的SPSite和SPWeb对象。
实际使用:
int currentUserID = Web.CurrentUser.ID;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (var site = new SPSite(Web.Url))
{
using (var web = site.OpenWeb())
{
//linq to sharepoint runwith required
var httpContext = HttpContext.Current;
try
{
//linq to sharepoint runwith required
HttpContext.Current = null;
using (ProjectManagementWebDataContext dc = new ProjectManagementWebDataContext(web.Url))
{
DeliveryItem delivery = new DeliveryItem();
delivery.Title = tbPart.Text;
delivery.PMId = currentUserID;
dc.Delivery.InsertOnSubmit(delivery);
dc.SubmitChanges();
//remaining code goes here...
}
}
catch (Exception ex)
{
JavaScript.Alert(string.Format("Error: {0}", ex.Message), this.Page);
return;
}
finally
{
//linq to sharepoint runwith required
HttpContext.Current = httpContext;
}
}
}
});