1

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?

1 Answer 1

1

I finally found a solution. Replacing this:

object[] args = methodInstance.GetMethod().CreateDefaultParameterInstances(methodInstance);

with this:

object[] args = { null, new List<Entity2>() };

will make it work. That is you instantiate your parameters directly instead of relying on the method instance to give you the collection. The null is used to store the return value but it can also be cast from the return value of entity.Execute().

I have not been able to figure out why this is the case but surprisingly the error message tells you exactly what the problem is. But I still can't figure out why you would need a parameterless constructor for all parameter type descriptors, especially if they are collections of other types which have parameterless constructors. Maybe someone can comment on that.

1
  • Make sure to mark this as an answer. Commented Apr 4, 2014 at 16:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.