Linq to Sharepoint(转)

http://weblogs.asp.net/uruit/archive/2011/05/05/linq-to-sharepoint-working-with-created-createdby-modified-and-modifiedby.aspx

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;
}

}
}
});

posted @ 2013-01-28 14:05  邑尘  阅读(693)  评论(0编辑  收藏  举报