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

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

时间: 2024-08-25 21:16:07

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

MVC在Java Web应用程序中的实现

一.MVC简介 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑. Model(模型)是应用程序中用于处理应用程序数据逻辑的部分. 通常模型对象负责在数据库中存取数据. View(视图)是应用程序中处理数据显示的部分. 通常视图是依据模型数据创建的. C

C++模版基于包含模型之外的显示实例化

一."经典模型"的失效 我们学过C++的人都知道,在C++中组织代码的经典模型是:将函数或类的声明和定义部分分开在不同的文件之中   , 即一般将声明放在一个.h的头文件中而定义在放在一个.cpp文件之中,当然这的确是写代码的一种很优良的风格,但问题 是如果将这种"经典模型"应用到模版上时就会发生连接上错误. 例如: 文件"A.h" #include"iostream" using namespace std; #pragma

Spring基于事件驱动模型的订阅发布模式代码实例详解

代码下载地址:http://www.zuidaima.com/share/1791499571923968.htm 原文:Spring基于事件驱动模型的订阅发布模式代码实例详解 事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): 当目标发送改变(发布),观察者(订阅者)就可以接收到改变: 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的

基于Select模型的混乱聊天室v1.0

最近在无聊完成了一个简单的基于select模型的匿名聊天室程序,均使用C++开发 服务器工作原理: 每接收一条客户端的信息,就将遍历所有的socket,并将该信息发给所有的客户端. 客户端使用两条线程,一个是接收服务端信息的线程,一个是等待阻塞输入的线程,获得输入时,将输入发送到服务器. 项目源码:https://github.com/coderguang/Chat 版本为v2.0的release. 其中ComLib也在github上 服务器核心代码: int main(int argc,cha

基于win32的socket编程及程序实现

初步研究了win32平台的Windows Sockets,它是Microsoft Windows的网络程序设计接口,它是从Berkeley Sockets扩展而来的,以动态链接库的形式提供给我们使用.包括流式套接字(提供面向连接.可靠的数据传输服务,数据无差错.无重复的发送,且按发送顺序接收.)和数据报套接字(提供无连接服务.数据包以独立包形式发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱.).原始套接字. CS模型:在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户

基于乐理模型的算法作曲研究

Abstraction Musical composition is a sophisticated movement of thought that is unique for humans. More concretely, composition reflects the basic technology and theory of music, i.e. harmonics, polyphony, orchestration, structure and so on, which are

京东评论情感分类器(基于bag-of-words模型)

最近在本来在研究paraVector模型,想拿bag-of-words来做对比. 数据集是京东的评论,经过人工挑选,选出一批正面和负面的评论. 实验的数据量不大,340条正面,314条负面.我一般拿200正面和200负面做训练,剩下做测试. 做着做着,领悟了一些机器学习的道理.发现,对于不同的数据集,效果是不同的. 对于特定的数据集,随便拿来一套模型可能并不适用. 对于这些评论,我感觉就是bag-of-words模型靠谱点. 因为这些评论的特点是语句简短,关键词重要. paraVector模型感

C语言 linux环境基于socket的简易即时通信程序

转载请注明出处:http://www.cnblogs.com/kevince/p/3891033.html   By Kevince 最近在看linux网络编程相关,现学现卖,就写了一个简易的C/S即时通信程序,代码如下: head.h 1 /*头文件,client和server编译时都需要使用*/ 2 #include <unistd.h> 3 #include <stdio.h> 4 #include <sys/types.h> 5 #include <sys

如何修改基于Debian包管理dpkg的程序流程方法概述

/*********************************************************************  * Author  : Samson  * Date    : 05/14/2014  * Test platform:  *              Mint 15-3.8.13.13  *              GNU bash, version 4.2.45  * ***************************************