转载

如何基于OM模型使用C#在程序中给SharePoint的BCS外部数据类型的字段赋值

概述:

外部内容类型和数据,SharePoint从2010这个版本开始就对BCS提供非常强大的支持,点点鼠标就可以取代以前直接编辑XML的方式来设置SharePoint到SQL数据库的连接。非常方便地在SharePoint中修改删除SQL数据库的数据,并且SharePoint还提供了字段级的支持,您可以在任何List当中插入一个External Data外部数据字段,用来引用SQL表中的某一行,并显示指定字段的值。 我们经常要用到程序去自动滴修改值,这个类型栏的值,是可以直接通过“Iiem[Field]=Value”这个语句简简单单地把它更改了的嘛?答案是否定的,如果要改这个BCS类型的值,您可能需要十几行代码,我们慢慢给您开讲。

此时,您有没有觉得SharePoint就像一个万能插头一样,什么样的“数据”,都能插得进来呢? “公牛牌!” ,Oh no... 是 “母牛牌” ,你懂的!

准备工作

在SharePoint 2010 和 SharePoint 2013 当中我们可以通过SharePoinit Desinger很方便地设置一个基于SQL SERVER的或是其它数据源的,“外部内容类型”,这样我们就可以在SharePoint 查询、修改、添加这个数据表,如下图所示:

本教程不是初级入门教程,如果各位小学生不懂如何进行BCS的基本操作,那么我们的大神门在度娘上已经留下了大量的痕迹,尽情地去Search(色)吧。

假设,现在我们已经有了如下的其于BCS的字段叫“name”,如下图,它是从一个叫“dept stuff” 这个外部类型当中读取数据的,我们还勾选了的相关的 “部门、移动号码”,作为显示字段。

重要概念

要引用如下的3个DLL文件,

我的using 是这样的:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.SharePoint; using System.Xml; using Microsoft.SharePoint.BusinessData; using Microsoft.SharePoint.Administration; using Microsoft.SharePoint.BusinessData.SharedService; using System.Data; using Microsoft.BusinessData.Runtime; using Microsoft.BusinessData.MetadataModel; using Microsoft.BusinessData.MetadataModel.Collections; using System.Web; using Microsoft.SharePoint.BusinessData.Infrastructure; using System.Globalization;

1. 存了什么:Identity

其实就是数据库中作为“标识”和“主键”的那一列,在创建SharePoint的Entity(即实体)时,一定要把这个Identity选出来,这是后面进行编程的基础,如果不设定这个的话,只能“呵呵”你了,因为我也不知道会发生什么。

如下图,大家可以偷窥到,我们2个优秀的员工,包XX和蒋XX,所在的部门和移动号码,千万别认为你们所见的,就是在LIST所实际存储的,在External Data类型的字段中,除了Identity什么也不实际存储,那她们的“名字、部门、电话”,这些值是什么呢?

缓存!Cache!  (此处省略1000字原理),记住包括您建的这个叫name的栏,存储的也是Cache,所以当你天真的使用

item["name"]="奥巴马"

来赋值后,你会发现name:部门和name:移动号码,根本没有改变,不是因为我们没有员工叫 “奥巴马” ,而是Identity的问题,所以我们给这种类型字段赋新值,值并不重要,你必须要知道新值在数据库表中的Identity那列的值!

2. 在哪存的:SPField.RelatedField

那你要问了,这个Identity,既然不存储在所建的那个External Field里,那存储在哪里呢,YES! 就是在这个RelatedField里,在微软网站上,关于这个属性的说明,是如此简单和无节操,所以我们取Identity数据的时候要使用这样的语句,同样赋值也是:

string entityId= listItem[dataField.RelatedField].ToString();                         

3. 怎么加密存的:EntityInstanceIdEncoder

天哪,知道存了什么,存在哪里,读出来却是乱码一片,经过大神Dosboy的研究发现了,这个Identity,竟然是加密码保存的,用得就是这个加密的方法。这是要把人整死的节奏嘛?

测试看看是不是加密: EntityInstanceIdEncoder.IsEncodedIdentifier

用来解密: EntityInstanceIdEncoder.DecodeEntityInstanceId

所以读取Identity的语句应该是这样子的:

 1                SPBusinessDataField dataField = listItem.Fields["name"] as SPBusinessDataField;  2                         string entityId= listItem[dataField.RelatedField].ToString();  3                         Identity id =null;  4                         if (EntityInstanceIdEncoder.IsEncodedIdentifier(entityId))  5                         {  6                             object[] oIDList = EntityInstanceIdEncoder.DecodeEntityInstanceId(entityId);  7                             id = new Identity(oIDList[0]);  8   9  10                         } 11                         else 12                             id = new Identity(entityId);

取出来的变量id,就是Identity类型的。如果要显示出来,就用这样的:

Console.WriteLine(id.GetIdentifierValues()[0].ToString ());

搞清楚外部数据External Data相关的存储的情况以后,我们就可以赋值的操作了

给External Data栏赋值的过程

1. 搞清楚你要赋的值在源数据库表中那个"主键"的栏的值是多少?

有些人就说了,兄弟我只知道新值,比如本例叫“本.拉灯”,那怎么办,对不起,请在程序中编程查询ID的值,比如“本.拉灯”的员工号(一定很排前)。这是前提,否则不是违背了External Data的原本意义了嘛,就是通过让你选一行数据,然后显示数据库中的值。

2. 给 RelatedField 赋 Identity的值,并根据Identity的值找到External Entity中的新值的那行:

public static IEntityInstance GetEntityInstance(SPBusinessDataField dataField, string entityId, SPSite site, SPListItem item) {  SPServiceContext context = SPServiceContext.GetContext(site);  IMetadataCatalog catalog = null;  BdcService bdcService = SPFarm.Local.Services.GetValue<BdcService>(String.Empty);  if (null != bdcService)  {   catalog = bdcService.GetDatabaseBackedMetadataCatalog(context);  }  IEntity entity = catalog.GetEntity(dataField.EntityNamespace, dataField.EntityName);  ILobSystem lobSystem = entity.GetLobSystem();  ILobSystemInstance LobSysteminstance = lobSystem.GetLobSystemInstances()[dataField.SystemInstanceName];  IEntityInstance entInstance = null;  // Get methods collection   foreach (KeyValuePair<string, IMethod> method in entity.GetMethods())  {   // Get current method’s instance    IMethodInstance methodInstance = method.Value.GetMethodInstances()[method.Key];   // Execute specific finder method.    if (methodInstance.MethodInstanceType == MethodInstanceType.SpecificFinder)   {       Identity id = null;    if (EntityInstanceIdEncoder.IsEncodedIdentifier(entityId))    {     object[] oIDList = EntityInstanceIdEncoder.DecodeEntityInstanceId(entityId);     id = new Identity(oIDList[0]);     // Execute specific finder method and get the entity instance      entInstance = entity.FindSpecific(id, entity.GetLobSystem().GetLobSystemInstances()[0].Value);     item[dataField.RelatedField] = entityId.ToString();    }    else    {     object oID = GetTypedIDValue(entityId, entity);     id = new Identity(oID);     string encodedIdentifier = EntityInstanceIdEncoder.EncodeEntityInstanceId(new object[] { oID });     // Execute specific finder method and get the entity instance        // Console.WriteLine(entity.Name + ":" + entity.GetLobSystem().GetLobSystemInstances()[0].Value.Name);     entInstance = entity.FindSpecific(id, entity.GetLobSystem().GetLobSystemInstances()[0].Value);     item[dataField.RelatedField] = encodedIdentifier;    }   }  }  return entInstance; } public static object GetTypedIDValue(string sID, IEntity oEntity) {  IIdentifierCollection type = oEntity.GetIdentifiers();  String sIdentifierType = type[0].IdentifierType.FullName.ToLower().Replace("system.", String.Empty);  object oID = null;  //find the instance value based on the given identifier type  switch (sIdentifierType)  {   case "string":    oID = sID;    break;   case "datetime":    oID = DateTime.Parse(sID, CultureInfo.CurrentCulture);    break;   case "boolean":    oID = Boolean.Parse(sID);    break;   case "int64":    oID = Int64.Parse(sID);    break;   case "int32":    oID = Int32.Parse(sID);    break;   case "int16":    oID = Int16.Parse(sID);    break;   case "double":    oID = Double.Parse(sID);    break;   case "char":    oID = Char.Parse(sID);    break;   case "guid":    oID = new Guid(sID);    break;   default:    oID = sID;    break;  }  return oID; } 

以上的代码涉及很多关于BCS很多很多的概念,什么实例什么实体,我只想说,你就复制、粘贴吧,你唯一要搞清楚的就是2件事件:

  • 列表的Externl Data(就是外部类型)的栏的名字,还有你网站的URL是什么。
  • 新值,的Identity是什么。

3. 给其它显示的栏 赋 显示的值

第2步做完后,就要给其它栏,本例是名字(对的也属于其它栏)、手机、部门,赋显示的值哦,用这个代码:

public static void SetSecondaryFields(SPListItem listItem, SPBusinessDataField dataField, IEntityInstance entityInstance)     {  // Convert the entity to a formatted datatable  DataTable dtBDCData = entityInstance.EntityAsFormattedDataTable;  // Set the BCS field itself (Display Value)  listItem[dataField.Id] = dtBDCData.Rows[0][dataField.BdcFieldName].ToString();  // Get the specific finder method to get the columns that returns  IMethodInstance method = entityInstance.Entity.GetMethodInstances(MethodInstanceType.SpecificFinder)[0].Value;  ITypeDescriptorCollection oDescriptors = method.GetReturnTypeDescriptor().GetChildTypeDescriptors()[0].GetChildTypeDescriptors();  // Set the column names to the correct values  foreach (ITypeDescriptor oType in oDescriptors)  {      if (oType.ContainsLocalizedDisplayName())      {   if (dtBDCData.Columns.Contains(oType.Name))   {       dtBDCData.Columns[oType.Name].ColumnName = oType.GetLocalizedDisplayName();   }      }  }  // get the secondary field display names; these should be set  string[] sSecondaryFieldsDisplayNames = dataField.GetSecondaryFieldsNames();  // loop through the fields and set each column to its value  foreach (string columnNameint in sSecondaryFieldsDisplayNames)  {      Guid gFieldID = listItem.Fields[String.Format("{0}: {1}", dataField.Title, columnNameint)].Id;      listItem[gFieldID] = dtBDCData.Rows[0][columnNameint].ToString();  }  listItem.Update();     } } 

以上还是涉及涉及很多概念,不用管,直接,复制、粘贴这个函数就行。

4. 示例如何在命令行程序中使用如上的代码:

把上面3个函数,把在一个静态的类中,我们叫myF,然后在Main函数中,写上如下的代码,这个代码是做这样的事情的.

这个网站集的URL是:http://r720/sites/demo

列表的名称是:External Field

外部数据列叫:name (附带显示:部门、移动号码2列)

我现在要把所有的行,的name栏都换成比刚才2位优秀员工更优秀的员工:本拉灯(他的代号200),代码如下,这个你不能复制粘贴,要换成自己的网站的情况:)

using (SPSite spSite = new SPSite("http://r720/sites/demo")) {  using (SPWeb spWeb = spSite.RootWeb)  {   SPList list = spWeb.Lists["External Field"];   foreach (SPListItem  listItem  in list.Items)   {    SPBusinessDataField dataField = listItem.Fields["name"] as SPBusinessDataField;   IEntityInstance entityinst = myF.GetEntityInstance(dataField, "200",new SPSite("http://r720/sites/demo"), listItem);   myF.SetSecondaryFields(listItem, dataField, entityinst);   }  } } Console.ReadLine(); 

故事的核心就这么2个语句:

IEntityInstance entityinst = GetEntityInstance(【外部字段】, 【新值ID】,【网站集】,【当前列表项】); SetSecondaryFields(【当前列表项】,【外部字段】,entityinst);

我们再看看效果吧,(千万别打电话哦,有美国人监听呢:))

正文到此结束
Loading...