lunes, 29 de diciembre de 2008

Definir Lookup Site Columns desde una Feature

Otra de las sorpresas que nos guarda Sharepoint son los campos lookup. Los campos lookup nos permiten tener desde las listas referencia a valores de otra listas. El problema viene cuando queremos crear una feature que contenga un tipo de campo Lookup para poder exportarlo a otro entorno. Esto se debe a que la definición de este tipo de campos lleva asociada el GUID de la lista y el GUID del web site donde se aloja, por lo que al exportarlo a una colección distinta no podremos hacerlo ya que la instancia de la lista de referencia tendrá un GUID distinto.

Googleando un poco he encontrado varias soluciones a esta carencia de sharepoint:

  • Definición del campo a nivel de lista en lugar de un site column
  • Creando un Feature Receiver que recalcule el id de la lista de referencia

Definición del campo a nivel de lista en lugar de un site column

Según algunas referencias de internet (http://blogs.msdn.com/joshuag/archive/2008/03/14/add-sharepoint-lookup-column-declaratively-through-caml-xml.aspx) en lugar de indicar el GUID de la lista en el campo "List", podemos indicar la URL de la lista. Lo malo es que lo que no dicen es que esto no funciona con los site column's, ya que solo es válido para columnas que definamos asociados a la propia lista.

Creando un Feature Receiver que recalcule el id de la lista de referencia

Consiste en recalcular el GUID de la lista de referencia al activar la característica.

Crearemos nuestro site column de forma normal y en la propiedad "List" indicaremos el nombre de la lista (no url). Esto hará que se cree el site column pero con una referencia errónea, por lo que al intentar utilizarlo nos dará un error al no encontrar la lista. Por lo que asociaremos a nuestra feature un FeatureReceiver que busque el guid de la lista en el sitio donde se está creando y lo reasigne al campo.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/>
<Field Type="Lookup"
DisplayName="Locations"
Required="FALSE"
List="LocationsList"
ShowField="LinkTitleNoMenu"
UnlimitedLengthInDocumentLibrary="FALSE"
Group="COBDemo"
ID="{6F26090A-C2AE-44d7-8F70-EE1663FE29F1}"
SourceID="{8c066b26-5a3e-4e1b-85ec-7e584cf178d7}"
StaticName="Locations"
Name="Locations"
/>
</Elements>

<Feature xmlns="http://schemas.microsoft.com/sharepoint/ Id="B188E645-F989-4baa-A109-D2313648432E"
Title="COB.Demo.ListBasedSiteColumns"
Description="Creates one of more site columns which get their data from lists (lookup fields).
The main definition of the columns is in CAML schema, but a feature receiver is used to fix up
the reference to the list. Both the feature and assembly deployment (to the GAC) are handled by COB.Demo.ListBasedSiteColumns.wsp."
Scope="Site" Hidden="FALSE"
Version="1.0.0.0"
ReceiverAssembly="COB.Demo.ListBasedSiteColumns, Version=1.0.0.0, Culture=neutral, PublicKeyToken=417a990752680f01"
ReceiverClass="COB.Demo.ListBasedSiteColumns.FeatureReceiver"
>
<ElementManifests>

................
</ElementManifests>
<Properties>
</Properties>
</Feature>

Existe un proyecto en codeplex SP2007LookupFields que implementa el FeatureReceiver que lo hace por nosotros. Solo tenéis que descargarlo, instalar el assembly y asociarlo en nuestra Feature.

Aunque existe otra solución que mejora SP2007LookupFields que hace que no tengas que indicar la ruta del fichero xml con la definición: http://mexicanratdog.wordpress.com/2007/10/01/create-lookup-site-columns-target-lists-through-a-feature/ ,en este ejemplo utilizan la propia definición de la Feature y buscan todos los campos del Tipo Lookup y les intenta cambiar el valor de la propiedad "List". Muy recomendable !!!

Solo una pequeña cuestión en este proyecto, y es que tiene un pequeño error que hace que se pueda realizar un Dispose sobre el RootWeb, el trozo de código que debéis corregir es el siguiente:

En lugar del código siguiente:

using (currentWeb)

{

........

}

lo sustituiremos por :

try{

.........

}finally{

if (!currentWeb.IsRootWeb)

currentWeb.Dispose();

}

A la hora de modificar el campo lookup desde el FeatureReceiver en ocasiones puede que tengamos problemas al borrar y volver a crear el site column ya que puede que tengamos una instancia y no podamos eliminarla. Para solucionarlo podemos reemplazar el código de la función createLookupColumn por el siguiente basado en el artículo: Field Definition Schema

private void createLookupColumn(SPWeb web, string sColumnDefinitionXml, string sColumnName)

{

SPFieldLookup lookupColumn = (SPFieldLookup)web.Fields[sColumnName];

lookupColumn.SchemaXml = sColumnDefinitionXml;

lookupColumn = (SPFieldLookup)web.Fields[sColumnName];

lookupColumn.LookupWebId = web.ID;

lookupColumn.Update();

}

1 comentario:

Mario Cortés Flores dijo...

Al final he tenido que retocar otro método ya que no me instanciaba correctamente el campo Lookup por lo que no me lo encontraba al acceder mediante CAML.


private string replaceListGuidString(string sFieldElement, string sListName, SPList referencedList)

{

string sListWithName = string.Format("List=\"{0}\"", sListName);

string sListWithGuid = string.Format("List=\"{0}\"", referencedList.ID);



string res = sFieldElement.Replace(sListWithName, sListWithGuid);

return res.Replace("xmlns=\"http://schemas.microsoft.com/sharepoint/\"", "");

}