SharePoint Consulting: Solutions to Common BCS Errors

Solving BCS Errors with SharePoint Consulting

My recent SharePoint consulting work has involved working through a few BCS errors. Programmatically accessing BCS External Lists in SharePoint is a bit like working in a parallel universe.  Most list access rules will continue to apply, however there are some very special caveats that one must remember.

For the reader’s findability convenience, I am organizing this guide in terms of the errors that the user will most likely encounter.

Reading and querying an External List

“The given key was not present in the dictionary”

This error may appear if any one of the CAML query conditions have not been met:

  • Viewfields were not specified
  • Viewfields and Query were specified via the ViewFields property (as opposed to using the ViewXML and Query properties)
  • The Method name was not included.  In most cases this should be either ‘Read List’ or ‘ReadList’.

Here is an example of a correctly laid out CAML query for BCS.

SPQuery query = new SPQuery();

query.ViewXml = @”

<View>

<Method Name=’Read List’/>

<Query>

<Where>

<Eq>

<FieldRef Name=’SUBMISSION_ID’/>

<Value Type=’Text’>FilterValHere</Value>

</Eq>

</Where>

</Query>

<ViewFields>

<FieldRef Name=’SUBMISSION_ID’/>

<FieldRef Name=’PACKAGE_ID’/>

</ViewFields></View>”;

“The Finder ‘ReadList’ cannot be found in ViewGroup associated with SpecificFinder (Read Item) operation ‘ReadItem’ in EntityNamespace”

This sort of error can appear if an incorrect Method name was supplied above.  Pay attention to caps and spaces.  In my own case, I had to pull open SharePoint Designer and check the exact name of the Read List operation, and I found that there was a space in the method name.

The shim execution failed unexpectedly – Proxy creation failed. Default context not found..

This error will appear if you did not declare the SPServiceContextScope.  You can perform this operation as shown below.  Note that the scope must be declared BEFORE the SPWeb is instantiated.

using (SPSite site = new SPSite(“http://mysite”))

{

var context = SPServiceContext.GetContext(site);

using (var scope = new SPServiceContextScope(context))

{

using (SPWeb web = site.RootWeb)

{

SPList myList = _web.Lists[“myList”];

SPQuery query = new SPQuery();

….

}

}

}

Writing to External Data columns / External Content Types

Setting values to External Data type columns require additional operations in order for the item to correctly linked to External Data source.  This is evident as one tries an operation like:

SPList submissionList = _web.Lists[_submissionListTitle];

SubmissionList.Items[0][ExternalDataCol] = “New value”

This operation will not change the “additional fields” columns.  This problem can be resolved by using the following commands and methods…

private static IEntityInstance GetEntityInstance<T>(SPSite site, string nameSpace, string entityName, T entityId)

{

var svcContext = SPServiceContext.GetContext(site);

using (var scope = new SPServiceContextScope(svcContext)) {

BdcService service = SPFarm.Local.Services.GetValue<BdcService>();

IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog(svcContext);

IEntity entity = catalog.GetEntity(nameSpace, entityName);

ILobSystemInstance LobSysteminstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value;

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)

{

// Create new identity

Identity id = new Identity(entityId);

// Execute specific finder method and get the entity instance

entInstance = entity.FindSpecific(id, entity.GetLobSystem().GetLobSystemInstances()[0].Value);

}

}

return entInstance;

}

}

private 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();

}

}

public SPListItem SetExternalDataCol<T>(SPListItem item, SPSite site, string ExternalDataColName, string ExternalContentTypeName, T fieldId)

{

SPBusinessDataField dataField = item.Fields[ExternalDataColName] as SPBusinessDataField;

item[dataField.RelatedField] = fieldId;

SetSecondaryFields(item, dataField, GetEntityInstance(site, site.Url, ExternalContentTypeName, fieldId));

return item;

}

The methods can be executed using this example code:

using (SPSite site = new SPSite(“http://mysite”))

{

using (SPWeb web = site.RootWeb)

{

SPList list = web.Lists[“My List”];

SPListItem newItem = list.AddItem();

newItem[_properties.Column_TemplateID_List_SubmissionTasks] = templateCollection[i][“ID”];

newItem = SetExternalDataCol(newItem, site,  “External Data Column Name”, “My External Content Type”, “External Column ID”);

newItem.Update();

}

}

 For more, check out what our SharePoint consulting team is up to in our Knowledge Base.