Thursday, April 28, 2011

Using Dynamic Stored Procedures in BCS Finders

We use quite a lot of Business Connectivity Services (BCS) at my current SharePoint 2010 project both for traditional integration of data from external systems into web-parts and lists, and also for crawling external systems for integrating those system using search and search-driven web-parts.

One of our integration partners prefers to provide their integration points as SQL Server 2008 stored procedures, which is very well supported by BCS. BCS supports both stored procedures and table valued functions, called "routines" in SharePoint Designer (SPD). SharePoint Designer is dependent on being able to extract metadata about the returned table data set when adding External Content Type (ECT) operations or when using the Operations Design View.

Alas, the provided integration sprocs used dynamic SQL statements, and for technical reasons this could not be rewritten to inline SQL select statements. This is as always a problem with tooling such as SPD, as no result set metadata can be discovered. When connecting SPD to the external system, I got no fields in the Data Source Elements panel in the Read List operation's Return Parameter Configuration. Rather I got three errors and a warning.


The workaround is quite simple and requires the use of a SQL Server table variable, which defines the result set and allows SPD to discover the table metadata. Rewrite the stored procedure by declaring a table variable, insert the result of the dynamic SQL statement into the variable, and finally return the result set by reading the table variable. The changes to the sproc is shown in blue in this example:

CREATE PROCEDURE [dbo].[GetFavorites]
AS
BEGIN
SET NOCOUNT ON;
 
DECLARE @DbName AS NVARCHAR(max) = 'ARISModellering1'
DECLARE @ObjDef AS NVARCHAR(max) = dbo.GetArisTableName(@DbName, 'ObjDef')
DECLARE @Model AS NVARCHAR(max) = dbo.GetArisTableName(@DbName, 'Model')
 
DECLARE @FavoriteSQL AS NVARCHAR(max) = N'
SELECT
ARISBPDATA.BOOKMARKS.ID AS FavoriteId
, ARISBPDATA.BOOKMARKS.DESCRIPTION AS FavoriteName
, ModelType.ModelTypeName AS FavoriteType
, LOWER(ARISBPDATA.BOOKMARKS.USERNAME) AS UserName
, ''http://puzzlepart/index.jsp?ExportName=ARISModellering&modelGUID='
+ ARISBPDATA.BOOKMARKS.DATAKEY AS FavoriteUrl
FROM
ARISBPDATA.BOOKMARKS
INNER JOIN ' + @Model + ' m ON ARISBPDATA.BOOKMARKS.OBJID = m.Id
INNER JOIN ModelType ON m.TypeNum = ModelType.ModelTypeId
'
 
 
DECLARE @userFavs TABLE(FavoriteId int not null, FavoriteName nvarchar(max), 
FavoriteType nvarchar(max), UserName nvarchar(max), FavoriteUrl nvarchar(max))
 
insert @userFavs EXEC sp_executeSQL @FavoriteSQL
 
select * from @userFavs
 
END

Refreshing the external system data connection and then creating the ECT read list operation now works fine, and all the return type errors and warnings are gone.


Note that the classic #temp table workaround won't work with SPD, you have to use a table variable in your stored procedure. The sproc will now use more memory, so the BCS best practice for keeping finder result sets small applies.

The table_variable declaration is also a good place to make sure that the identifier column is "not null" and that it is a supported BCS data type such as "int32". External lists cannot be created from an ECT whose identifier field is unsupported, such as SQL Server "bigint", and I strongly recommend using a supported identifier data type right from the start. Getting the ECT identifier wrong in the BCS model will give you problems later on when using SharePoint Designer.

3 comments:

Joseph, Ben said...

You can use #temp table on stored procedure.
Some times when we user Substring, CharIndex Sharepoint designer will not allow you to create any operations.
Create a dummy stored procedure with all columns in the original stored procedure and create operations.
Once operatinos are done and save BDC then export BDC and change stored procedure name with the real stored procedure.
or you can convert dummy stored procedure as the original.
It will work.

Please let me know if you have any questions.
Thanks
Benson

Ramkumar Krishnan said...

This saved more time for us. Thank much on-behalf of my entire team.

Anonymous said...

This saved me! You are a life saver!