I have a problem using collections for in-parameters with BCS entity methods and since I'm pretty sure you should be able to do this there must be some error that I haven't found.
I have created a new Business Data Connectivity Model in Visual Studio 2010 and modified the "ReadList" method to accept 1 in-parameter. The parameter is simply a collection of a custom entity class that I have created (Entity2.cs), setting the type of the type descriptor to IEnumerable<Entity2>. The method also returns a collection of Entity2 instances (IEnumerable<Entity2>) as you can see from the code below.
This is how Entity2.cs looks like:
using System;
namespace BdcModelProject1.BdcModel1
{
public partial class Entity2
{
public Entity2()
{
}
public Entity2(string entityName, string entityValue)
{
EntityName = entityName;
EntityValue = entityValue;
}
public string EntityName
{
get;
set;
}
public string EntityValue
{
get;
set;
}
}
}
This is how the service-class was implemented:
using System;
using System.Collections.Generic;
namespace BdcModelProject1.BdcModel1
{
public class Entity1Service
{
public static IEnumerable<Entity2> ReadList(IEnumerable<Entity2> parameter)
{
return parameter;
}
}
}
This is how the bdcm-file looks like:
<?xml version="1.0" encoding="utf-8"?>
<Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/windows/2007/BusinessDataCatalog" Name="BdcModel1">
<LobSystems>
<LobSystem Name="BdcModel1" Type="DotNetAssembly">
<LobSystemInstances>
<LobSystemInstance Name="BdcModel1" />
</LobSystemInstances>
<Entities>
<Entity Name="Entity1" Namespace="BdcModelProject1.BdcModel1" EstimatedInstanceCount="1000" Version="1.0.0.12">
<Properties>
<Property Name="Class" Type="System.String">BdcModelProject1.BdcModel1.Entity1Service, BdcModel1</Property>
</Properties>
<Identifiers>
<Identifier Name="Identifier1" TypeName="System.String" />
<!-- TODO: Change the name of the ID and if needed the TypeName of your identifier. -->
</Identifiers>
<Methods>
<!-- start finder method -->
<Method Name="ReadList">
<!-- TODO: Change the name of the method if needed. -->
<Parameters>
<Parameter Direction="Return" Name="returnParameter">
<TypeDescriptor TypeName="System.Collections.Generic.IEnumerable`1[[BdcModelProject1.BdcModel1.Entity2, BdcModel1]]" IsCollection="true" Name="Entity1List">
<TypeDescriptors>
<TypeDescriptor TypeName="BdcModelProject1.BdcModel1.Entity2, BdcModel1" Name="Entity2" IsCollection="false">
<TypeDescriptors>
<TypeDescriptor TypeName="System.String" IdentifierName="Identifier1" Name="Identifier1" />
<TypeDescriptor TypeName="System.String" Name="Message" />
<!-- TODO: Add TypeDescriptors when you add properties to Entity1. -->
</TypeDescriptors>
</TypeDescriptor>
</TypeDescriptors>
</TypeDescriptor>
</Parameter>
<Parameter Name="parameter" Direction="In">
<TypeDescriptor Name="parameterTypeDescriptor" TypeName="System.Collections.Generic.IEnumerable`1[[BdcModelProject1.BdcModel1.Entity2, BdcModel1]]" IsCollection="true">
<TypeDescriptors>
<TypeDescriptor Name="TypeDescriptor" TypeName="BdcModelProject1.BdcModel1.Entity2, BdcModel1">
<TypeDescriptors>
<TypeDescriptor Name="TypeDescriptor" TypeName="BdcModelProject1.BdcModel1.Entity2, BdcModel1" IsCollection="false" />
</TypeDescriptors>
</TypeDescriptor>
</TypeDescriptors>
</TypeDescriptor>
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Type="Finder" ReturnParameterName="returnParameter" Default="true" Name="ReadList" DefaultDisplayName="Entity1 List" />
</MethodInstances>
</Method>
<!-- end finder method -->
<!-- start specific finder method -->
<!-- end specific finder method -->
</Methods>
</Entity>
</Entities>
</LobSystem>
</LobSystems>
</Model>
Then I use this code to call the ReadList method:
const string entityNamespace = "BdcModelProject1.BdcModel1";
const string entityName = "Entity1";
const string methodName = "ReadList";
using(SPSite site = new SPSite(SPContext.Current.Site.ID))
{
using(new SPServiceContextScope(SPServiceContext.GetContext(site)))
{
var bdcService = SPFarm.Local.Services.GetValue<BdcService>();
IMetadataCatalog metadataCatalog = bdcService.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current);
IEntity entity = metadataCatalog.GetEntity(entityNamespace, entityName);
ILobSystem lobSystem = entity.GetLobSystem();
ILobSystemInstance lobSystemInstance = lobSystem.GetLobSystemInstances()[0].Value;
IMethodInstance methodInstance = entity.GetMethodInstance(methodName, MethodInstanceType.Finder);
object[] args = methodInstance.GetMethod().CreateDefaultParameterInstances(methodInstance);
...
}
}
When I try and execute this code I get an error saying that "There is no parameterless Constructor for the Type System.Collections.Generic.IEnumerable". What I don't understand is that the type is not suppose to have a constructor at all - it only represents a collection of Entity2 instances. If I change the in-parameter to accept an Entity2 object instead of a collection the code works fine. Does someone have a suggestion as to why this error occurs?