如何基于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);

 

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

 

posted @ 2015-05-26 12:12  dosboy  阅读(953)  评论(3编辑  收藏  举报