In SharePoint 2010 there are a lot of possible sources for External Content Types. Next to the default ones (WCF, Web Service, SQL), SP allows the creation of custom BDC Models using Visual Studio 2010. By using a custom Model you can use any source that you can access with Code.
In the following example, I will create a custom BDC Model for using a SharePoint List as a Source.
Create Visual Studio Project
- Create a new Visual Studio Project of Type "Business Data Connectivity Model".
Note: Remember that SharePoint 2010 uses .NET Framework 3.5 and not 4
- Enter the url and "Deploy as a farm solution"
- Visual Studio will generate
- a Package, which is deployed to SharePoint
- a Feature, which is added to the Package
- a default BDC Model, a xml description of the Entity (There is also a visual editor)
- a default Entity, a code description of the Entity
Create xml Entity
Visual Studio knows 3 visual ways to adapt the xml Entity:
- Use the BDC Method Details window to define the parameters, instances, and filter descriptors of a method.
Step 1
Remove all default created methods in the Method Details windows.
Step 2
Rename the Entity to "Customer"
Rename the default Identifier to anything that suits your needs, I decided to use the ItemID of type System.Int32. This field will hold the unique ItemID of any SharePoint Item.
Step 3
In the "BDC Method Details" view generate a "Specific Finder" Method for reading an item in the list. The parameters for the method will be automatically generated for you.
Step 4
Adapt the Customer TypeDescriptor in the BDC Explorer. Add TypeDescriptor fields for each field that you want to have in each customer entity e.g. FirstName (String), LastName (String) and of course the identifier ItemID (Integer).
Since ItemID is the field related to your identifier, you have to set additional properties for that TypeDescriptor:
- 'Identifier' Property -> select ItemID (the link to the identifier value in the entity)
- 'Read-only' Property -> set to True (since ItemID will be linked to the SharePoint ItemID in the source, we do not want the user to be able to change this value)
After adapting one Customer TypeDescriptor, these changes will be used for any newly generated method.
Step 5
Create methods for the other operations: 'Finder' (Read List), 'Creator' (Create Item), 'Updater' (Update Item) and 'Deleter' (Delete Item)
In the Create Method adapt the NewCustomer TypeDescriptor by removing the ItemID TypeDescriptor, since we don't want the user to be able to enter a value for this field.
Create Code Entity
In the Solution Explorer you can find a code file called "Entity1.cs". In this file the code is stored that links the fields defined in the xml entity to code fields.
Step 1
Create a property for each of the fields that you want to have for each customer. e.g.
public int ItemID { get; set; } public string LastName { get; set; } public string FirstName { get; set; } |
Create Code for Service
In the Solution Explorer you can find a code file called "CustomerService.cs". In this file the code is stored that reads the items from any source and stores them in BDC Entities.
Step 1
At the beginning of the class you will find the example methods, which were generated with the project. These can be deleted. Only keep the methods that have "throw
new System.NotImplementedException();" in their body.
Step 2
In my example I used the SharePoint Object Model for retrieving data from SharePoint. I generated a method that would create a Customer Entity on basis of a SharePoint List Item that contains the information about a Customer:
private static Customer generateCustomer(SPListItem customerItem) { Customer myCustomer = new Customer(); myCustomer.ItemID = customerItem.ID; myCustomer.FirstName = customerItem["First Name"].ToString(); myCustomer.LastName = customerItem["Last Name"].ToString(); return myCustomer; } |
Step 3
Write the code for the different methods:
ReadItem(int itemID) | Customer myCustomer = null; using (SPSite oSite = new SPSite(http://sp2010.tripleaconnected.com/personal/KS)){ using (SPWeb oWeb = oSite.OpenWeb()) { SPList oList = oWeb.Lists["Contacts"]; if (oList != null) { SPListItem customerItem = oList.GetItemById(itemID); if (customerItem != null) { myCustomer = generateCustomer(customerItem); } } } } return myCustomer; |
ReadList() | List<Customer> customers = new List<Customer>(); using (SPSite oSite = new SPSite(http://sp2010.tripleaconnected.com/personal/KS)){ using (SPWeb oWeb = oSite.OpenWeb()) { SPList oList = oWeb.Lists["Contacts"]; foreach(SPListItem customerItem in oList.Items){ customers.Add(generateCustomer(customerItem)); } } } return customers; |
Create(Customer newCustomer) | Customer returnCustomer = null; using (SPSite oSite = new SPSite(http://sp2010.tripleaconnected.com/personal/KS)){ using (SPWeb oWeb = oSite.OpenWeb()) { SPList oList = oWeb.Lists["Contacts"]; SPListItem customerItem = oList.AddItem(); customerItem["First Name"] = newCustomer.FirstName; customerItem["Last Name"] = newCustomer.LastName; customerItem.Update(); SPListItem returnCustomerItem = oList.GetItemByID(customerItem.ID); if (returnCustomerItem != null) { returnCustomer = generateCustomer(returnCustomerItem); } } } return returnCustomer; |
Update(Customer customer) | using (SPSite oSite = new SPSite(http://sp2010.tripleaconnected.com/personal/KS)){ using (SPWeb oWeb = oSite.OpenWeb()) { SPList oList = oWeb.Lists["Contacts"]; SPListItem customerItem = oList.GetItemById(customer.ItemID); if (customerItem != null) { customerItem["First Name"] = customer.FirstName; customerItem["Last Name"] = customer.LastName; customerItem.Update(); } } } |
Delete(int itemID) | using (SPSite oSite = new SPSite ("http://sp2010.tripleaconnected.com/personal/KS")) { using (SPWeb oWeb = oSite.OpenWeb()) { SPList oList = oWeb.Lists["Contacts"]; SPListItem customerItem = oList.GetItemById(itemID); if (customerItem != null) { customerItem.Delete(); } } } |
Note:
When writing this code file see the Best Practices for Error Handling: http://msdn.microsoft.com/en-us/library/ff464398.aspx
Deploy
You can now deploy the project and create a new External List based on this BDC Model.
Note:
When trying to deploy a Business Data Connectivity Model with Visual Studio 2010 you might get the following error:
Error occurred in deployment step 'Add Solution': Property 'SiteUrl' contains an invalid URL
Solution:
Add a property to the Feature.xml File:
<Properties>
<Property Key="SiteUrl" Value="http://sp2010.tripleaconnected.com">
</Properties>