Пример #1
0
        public ArtDevBCS(string ModelName)
        {
            this.ModelName = ModelName;
            // Get the Catalog for the SharePoint site
            BdcService service = SPFarm.Local.Services.GetValue <BdcService>(String.Empty);
            SPAdministrationWebApplication centralWeb = SPAdministrationWebApplication.Local;
            SPSite           AdminSite = new SPSite(centralWeb.Sites.FirstOrDefault <SPSite>().Url);
            SPServiceContext context   = SPServiceContext.GetContext(AdminSite);

            this.catalog =
                service.GetAdministrationMetadataCatalog(context);

            this.catalog.GetModels(ModelName)?.ToList().ForEach(m => m.Delete());
            // Create a new Model
            // NOTE: Assume that the "ModelName" Model
            // does not already exist.
            this.Model = Model.Create(ModelName, true, catalog);
        }
        // Uncomment the method below to handle the event raised after a feature has been activated.

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            // Get the Catalog for the SharePoint site
            BdcService service =
                SPFarm.Local.Services.GetValue <BdcService>(String.Empty);
            SPSite           site    = new SPSite("http://sp2016:2016/");
            SPServiceContext context = SPServiceContext.GetContext(site);
            AdministrationMetadataCatalog catalog =
                service.GetAdministrationMetadataCatalog(context);


            catalog.GetModels("EmployeeModel")?.ToList().ForEach(m => m.Delete());
            // Create a new Employee Model
            // NOTE: Assume that the "EmployeeModel" Model
            // does not already exist.
            Model EmployeeModel = Model.Create("EmployeeModel", true, catalog);


            // Make a new Employee LobSystem
            // NOTE: Assume that the "AdventureWorks" LobSystem
            // does not already exist.
            LobSystem adventureWorksLobSystem = EmployeeModel.OwnedReferencedLobSystems.Create("AdventureWorks", true, SystemType.Database);

            // Make a new AdventureWorks LobSystemInstance.
            LobSystemInstance adventureWorksLobSystemInstance = adventureWorksLobSystem.LobSystemInstances.Create("AdventureWorks", true);

            // Set the connection properties.
            adventureWorksLobSystemInstance.Properties.Add(
                "ShowInSearchUI", "");
            adventureWorksLobSystemInstance.Properties.Add(
                "DatabaseAccessProvider", "SqlServer");
            adventureWorksLobSystemInstance.Properties.Add(
                "RdbConnection Data Source", "SP2016");
            adventureWorksLobSystemInstance.Properties.Add(
                "RdbConnection Initial Catalog", "AdventureWorks2016");
            adventureWorksLobSystemInstance.Properties.Add(
                "AuthenticationMode", "RdbCredentials");
            adventureWorksLobSystemInstance.Properties.Add(
                "SsoProviderImplementation", "Microsoft.Office.SecureStoreService.Server.SecureStoreProvider, Microsoft.Office.SecureStoreService, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
            adventureWorksLobSystemInstance.Properties.Add(
                "SsoApplicationId", "Adventure");
            adventureWorksLobSystemInstance.Properties.Add(
                "RdbConnection Pooling", "true");

            // Create a new Employee Entity.
            Entity EmployeeEntity = Entity.Create(
                "Employee",
                "AdventureWorks",
                true,
                new Version("1.0.0.4"),
                10000,
                CacheUsage.Default,
                adventureWorksLobSystem,
                EmployeeModel,
                catalog);

            // Set the identifier to the EmployeeID column.
            EmployeeEntity.Identifiers.Create(
                "BusinessEntityID", true, "System.Int32");

            // Create the Finder Method,
            // i.e. the method to return all rows.
            CreateReadListMethod(catalog, EmployeeEntity);

            // Create the Specific Finder Method,
            // i.e. the method to return one row.
            CreateReadItemMethod(catalog, EmployeeEntity);

            // Validate the Employee Entity.
            ActivationError[] activationErrors =
                EmployeeEntity.Validate();

            // Check if the validation failed.
            if (activationErrors.Count() == 0)
            {
                // The validation was successful so publish the Employee Entity.
                EmployeeEntity.Activate();
            }
        }
        private static void CreateReadItemMethod(
            AdministrationMetadataCatalog catalog, Entity contactEntity)
        {
            // Create the specific finder method
            Method getContactMethod = contactEntity.Methods.Create(
                "GetEmployee", true, false, "vEmployee");

            // Specify the query
            getContactMethod.Properties.Add(
                "RdbCommandText",
                "SELECT [BusinessEntityID] , [Title] , [FirstName] , [LastName] " +
                "FROM [HumanResources].[vEmployee] " +
                "WHERE [BusinessEntityID] = @BusinessEntityID");

            // Set the command type
            getContactMethod.Properties.Add("RdbCommandType", "Text");


            getContactMethod.Properties.Add(
                "Schema", "HumanResources");
            getContactMethod.Properties.Add(
                "BackEndObjectType", "SqlServerView");
            getContactMethod.Properties.Add(
                "BackEndObject", "vEmployee");

            // Create the ContactID input parameter
            Parameter BusinessEntityIDParameter =
                getContactMethod.Parameters.Create(
                    "@BusinessEntityID", true, DirectionType.In);

            // Create the TypeDescriptor for the ContactID parameter
            BusinessEntityIDParameter.CreateRootTypeDescriptor(
                "BusinessEntityID",
                true,
                "System.Int32",
                "BusinessEntityID",
                new IdentifierReference(
                    "BusinessEntityID",
                    new EntityReference("AdventureWorks", "Employee", catalog),
                    catalog),
                null,
                TypeDescriptorFlags.None,
                null,
                catalog);

            // Create the Contact return parameter
            Parameter contactParameter =
                getContactMethod.Parameters.Create(
                    "Employee", true, DirectionType.Return);

            // Create the TypeDescriptors for the Contact return parameter.
            TypeDescriptor returnRootCollectionTypeDescriptor =
                contactParameter.CreateRootTypeDescriptor(
                    "Employees",
                    true,
                    "System.Data.IDataReader, System.Data, Version=4.0.0.0," +
                    " Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    "Employees",
                    null,
                    null,
                    TypeDescriptorFlags.IsCollection,
                    null,
                    catalog);
            TypeDescriptor returnRootElementTypeDescriptor =
                returnRootCollectionTypeDescriptor.ChildTypeDescriptors.Create(
                    "Employee",
                    true,
                    "System.Data.IDataRecord, System.Data, Version=4.0.0.0," +
                    " Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    "Employee",
                    null,
                    null,
                    TypeDescriptorFlags.None,
                    null);

            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "BusinessEntityID",
                true,
                "System.Int32",
                "BusinessEntityID",
                new IdentifierReference("BusinessEntityID",
                                        new EntityReference("AdventureWorks", "Employee", catalog),
                                        catalog),
                null,
                TypeDescriptorFlags.None,
                null);
            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "LastName",
                true,
                "System.String",
                "LastName",
                null,
                null,
                TypeDescriptorFlags.None,
                null);
            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "FirstName",
                true,
                "System.String",
                "FirstName",
                null,
                null,
                TypeDescriptorFlags.None,
                null);
            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "Title",
                true,
                "System.String",
                "Title",
                null,
                null,
                TypeDescriptorFlags.None,
                null);

            // Create the specific finder method instance
            getContactMethod.MethodInstances.Create(
                "GetEmployee",
                true,
                returnRootElementTypeDescriptor,
                MethodInstanceType.SpecificFinder,
                true);
        }
        private static void CreateReadListMethod(
            AdministrationMetadataCatalog catalog, Entity contactEntity)
        {
            // Create the Finder method
            Method getContactsMethod = contactEntity.Methods.Create(
                "GetEmployees", true, false, "vEmployee");

            // Specify the query
            getContactsMethod.Properties.Add(
                "RdbCommandText",
                "SELECT TOP(@MaxRowsReturned) [BusinessEntityID] , [Title] , [FirstName] , [LastName] " +
                " FROM [HumanResources].[vEmployee]");

            // Set the command type
            getContactsMethod.Properties.Add("RdbCommandType", "Text");

            // Set the additional property values so that this
            // External Content Type can be displayed
            // in SharePoint Designer.
            getContactsMethod.Properties.Add(
                "Schema", "HumanResources");
            getContactsMethod.Properties.Add(
                "BackEndObjectType", "SqlServerView");
            getContactsMethod.Properties.Add(
                "BackEndObject", "vEmployee");


            // Create a Filter so that we can limit the number
            // of rows returned;
            // otherwise we may exceed the list query size threshold.
            FilterDescriptor limitRowsReturnedFilter =
                getContactsMethod.FilterDescriptors.Create(
                    "RowsReturnedLimit", true, FilterType.Limit, null);

            limitRowsReturnedFilter.Properties.Add(
                "IsDefault", true);

            // Create the RowsToRetrieve input parameter.
            Parameter maxRowsReturnedParameter =
                getContactsMethod.Parameters.Create(
                    "@MaxRowsReturned", true, DirectionType.In);

            // Create the TypeDescriptor for the MaxRowsReturned parameter.
            // using the Filter we have created.
            TypeDescriptor maxRowsReturnedTypeDescriptor =
                maxRowsReturnedParameter.CreateRootTypeDescriptor(
                    "MaxRowsReturned",
                    true,
                    "System.Int64",
                    "MaxRowsReturned",
                    null,
                    limitRowsReturnedFilter,
                    TypeDescriptorFlags.None,
                    null,
                    catalog);

            // Create the Contacts return parameter.
            Parameter contactsParameter =
                getContactsMethod.Parameters.Create(
                    "GetEmployees", true, DirectionType.Return);

            // Create the TypeDescriptors for the Contacts return parameter.
            TypeDescriptor returnRootCollectionTypeDescriptor =
                contactsParameter.CreateRootTypeDescriptor(
                    "Employees",
                    true,
                    "System.Data.IDataReader, System.Data, Version=4.0.0.0," +
                    " Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    "Employees",
                    null,
                    null,
                    TypeDescriptorFlags.IsCollection,
                    null,
                    catalog);
            TypeDescriptor returnRootElementTypeDescriptor =
                returnRootCollectionTypeDescriptor.ChildTypeDescriptors.Create(
                    "Employee",
                    true,
                    "System.Data.IDataRecord, System.Data, Version=4.0.0.0," +
                    " Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    "Employee",
                    null,
                    null,
                    TypeDescriptorFlags.None,
                    null);

            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "BusinessEntityID",
                true,
                "System.Int32",
                "BusinessEntityID",
                new IdentifierReference("BusinessEntityID",
                                        new EntityReference("AdventureWorks", "Employee", catalog),
                                        catalog),
                null,
                TypeDescriptorFlags.None,
                null);
            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "LastName",
                true,
                "System.String",
                "LastName",
                null,
                null,
                TypeDescriptorFlags.None,
                null);
            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "FirstName",
                true,
                "System.String",
                "FirstName",
                null,
                null,
                TypeDescriptorFlags.None,
                null);
            returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                "Title",
                true,
                "System.String",
                "Title",
                null,
                null,
                TypeDescriptorFlags.None,
                null);

            // Create the finder method instance
            MethodInstance readListMethodInstance =
                getContactsMethod.MethodInstances.Create(
                    "GetEmployees",
                    true,
                    returnRootCollectionTypeDescriptor,
                    MethodInstanceType.Finder,
                    true);

            readListMethodInstance.Properties.Add("RootFinder", "");

            // Set the default value for the number of rows
            // to be returned filter.
            // NOTE: The method instance needs to be created first
            // before we can set the default value.
            maxRowsReturnedTypeDescriptor.SetDefaultValue(
                readListMethodInstance.Id, Int64.Parse("10000000"));
        }
        /// <summary>
        /// Returns the AdministrationMetadataCatalog from the Url of the Site or WebApplication.
        /// </summary>
        /// <param name="siteUrlProperty">SiteUrl property used to get the SPSite.</param>
        /// <returns>AdministrationMetadataCatalog object.</returns>
        private void CreateAdministrationMetadataCatalog(SPFeatureProperty siteUrlProperty)
        {
            SPServiceContext context = null;
            SPSite site = null;

            try
            {
                site = GetSite(siteUrlProperty);
                context = SPServiceContext.GetContext(site);
            }
            finally
            {
                if (site != null)
                {
                    site.Dispose();
                }
            }

            var bdcService = parentFarm.Services.GetValue<BdcService>();
            if (bdcService == null)
            {
                throw new InvalidOperationException("Unable to contact BdcService.");
            }

            amc = bdcService.GetAdministrationMetadataCatalog(context);
            if (amc == null)
            {
                throw new InvalidOperationException("Unable to create AdministrationMetadataCatalog.");
            }
        }
        /// <summary>
        /// Creates the finder Method, specify the query it will use, and define the output parameters associated with it.
        /// The finder Method returns all of the rows of data from the data source which its query defines.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="table"></param>
        /// <param name="lobSystemName"></param>
        /// <param name="referenceList"></param>
        /// <param name="catalog"></param>
        /// <param name="entity"></param>
        private static void CreateReadListMethod(string name, string table, string lobSystemName, List<ExternalColumnReference> referenceList, AdministrationMetadataCatalog catalog, Entity entity)
        {
            string listMethodName = String.Format("Get{0}List", name);
            string listMethodEntity = name + "List";
            string itemMethodEntity = name;

            var identifierField = referenceList.Where(x => x.IsKey).ToList().First();
            if (identifierField == null)
                throw new NullReferenceException("Could not get identifier field.");

            // Create the Finder method
            Method getListMethod = entity.Methods.Create(listMethodName, true, false, table); // itemMethodEntity

            // Specify the query
            // "SELECT [CustomerId] , [FirstName] , [LastName] , [Phone] , [EmailAddress] , [CompanyName] FROM [Customers].[SalesLT].[Customer]"
            string queryAllItemsString = "SELECT TOP(@RowLimit) ";

            foreach(ExternalColumnReference reference in referenceList)
            {
                queryAllItemsString += "[" + reference.SourceName + "], ";
            }
            queryAllItemsString = queryAllItemsString.Substring(0, queryAllItemsString.Length - 2);
            queryAllItemsString += " FROM [" + table + "]";

            var whereClause = " WHERE";
            foreach (ExternalColumnReference reference in referenceList)
            {
                if (reference.IsSearchField)
                {
                    if (reference.Type == "System.String")
                    {
                        whereClause += String.Format(" ((@{1} IS NULL) OR ((@{1} IS NULL AND [{0}] IS NULL) OR [{0}] LIKE @{1})) AND", reference.SourceName, reference.DestinationName);
                    }
                    else
                    {
                        whereClause += String.Format(" ((@{1} = N'0') OR ((@{1} IS NULL AND [{0}] IS NULL) OR [{0}] = @{1})) AND", reference.SourceName, reference.DestinationName);
                    }
                }
            }

            if (whereClause.Length == 7)
                whereClause = "";
            else
            {
                whereClause = whereClause.Substring(0, whereClause.Length - 4);
            }

            queryAllItemsString += whereClause;

            // Set method properties
            getListMethod.Properties.Add("RdbCommandText", queryAllItemsString);
            getListMethod.Properties.Add("RdbCommandType", "Text");
            getListMethod.Properties.Add("BackEndObjectType", "SqlServerTable");
            getListMethod.Properties.Add("BackEndObject", table);
            getListMethod.Properties.Add("Schema", "dbo");

            // Create the Entity return parameter
            Parameter modelParameter = getListMethod.Parameters.Create(name, true, DirectionType.Return);

            // Create the TypeDescriptors for the Entity return parameter
            TypeDescriptor returnRootCollectionTypeDescriptor =
                modelParameter.CreateRootTypeDescriptor(
                    listMethodEntity,
                    true,
                    "System.Data.IDataReader, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    listMethodEntity,
                    null,
                    null, // filter descriptor
                    TypeDescriptorFlags.IsCollection,
                    null,
                    catalog);

            TypeDescriptor returnRootElementTypeDescriptor =
                returnRootCollectionTypeDescriptor.ChildTypeDescriptors.Create(
                    itemMethodEntity,
                    true,
                    "System.Data.IDataRecord, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    itemMethodEntity,
                    null,
                    null,
                    TypeDescriptorFlags.None,
                    null);

            // Create a Filter so that we can limit the number
            // of rows returned;
            // otherwise we may exceed the list query size threshold.
            FilterDescriptor limitRowsReturnedFilter =
                getListMethod.FilterDescriptors.Create(
                    "RowLimitFilter", true, FilterType.Limit, identifierField.DestinationName);

            limitRowsReturnedFilter.Properties.Add("IsDefault", false);
            limitRowsReturnedFilter.Properties.Add("UsedForDisambiguation", false);

            // Create the RowsToRetrieve input parameter.
            Parameter identifierParameter =
                getListMethod.Parameters.Create(
                "@RowLimit", true, DirectionType.In);

            // Create the TypeDescriptor for the MaxRowsReturned parameter.
            // using the Filter we have created.
            TypeDescriptor maxRowsReturnedTypeDescriptor =
                identifierParameter.CreateRootTypeDescriptor(
                    "RowLimit",
                    true,
                    "System.Int64",
                    identifierField.SourceName,
                    null,
                    limitRowsReturnedFilter,
                    TypeDescriptorFlags.None,
                    null,
                    catalog);

            var stringTypeDescriptorList = new List<TypeDescriptor>();
            var counter = 0;
            foreach (ExternalColumnReference reference in referenceList)
            {
                IdentifierReference identityReference = null;
                if(reference.IsKey)
                    identityReference = new IdentifierReference(reference.DestinationName, new EntityReference("EFEXCON.ExternalLookup", itemMethodEntity, catalog), catalog);

                if (reference.IsSearchField)
                {
                    FilterType filterType = reference.Type == "System.String" ? FilterType.Wildcard : FilterType.Comparison;
                    FilterDescriptor filter = getListMethod.FilterDescriptors.Create(
                        reference.DestinationName + "Filter", true, filterType, reference.DestinationName);

                    filter.Properties.Add("CaseSensitive", false);
                    filter.Properties.Add("IsDefault", false);
                    filter.Properties.Add("UsedForDisambiguation", false);
                    filter.Properties.Add("UseValueAsDontCare", true);
                    filter.Properties.Add("DontCareValue", "");

                    // Create the filter input parameter.
                    Parameter filterParameter = getListMethod.Parameters.Create(
                            "@" + reference.DestinationName, true, DirectionType.In);

                    // Create the TypeDescriptor for the filter parameter.
                    TypeDescriptor filterParamTypeDescriptor =
                        filterParameter.CreateRootTypeDescriptor(
                        reference.DestinationName,
                        true,
                        reference.Type,
                        reference.SourceName,
                        null,
                        filter,
                        TypeDescriptorFlags.None,
                        null,
                        catalog);

                    if (reference.Type == "System.String")
                        stringTypeDescriptorList.Add(filterParamTypeDescriptor);

                    if (counter > 0)
                        filterParamTypeDescriptor.Properties.Add("LogicalOperatorWithPrevious", "And");

                    counter++;
                }

                var childTypeDescriptor = returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                    reference.DestinationName,
                    true,
                    reference.Type,
                    reference.SourceName,
                    identityReference,
                    null,
                    TypeDescriptorFlags.None,
                    null
                );

                childTypeDescriptor.Properties.Add("ShowInPicker", true);
            }

            // Create the finder method instance
            MethodInstance readListMethodInstance =
                getListMethod.MethodInstances.Create(
                    listMethodName,
                    true,
                    returnRootCollectionTypeDescriptor,
                    MethodInstanceType.Finder,
                    true);

            readListMethodInstance.Properties.Add("RootFinder", "");

            // Set the default value for the number of rows
            // to be returned filter.
            // NOTE: The method instance needs to be created first
            // before we can set the default value.
            maxRowsReturnedTypeDescriptor.SetDefaultValue(
                readListMethodInstance.Id, Int64.Parse("30"));

            foreach(var typeDescriptor in stringTypeDescriptorList)
            {
                typeDescriptor.SetDefaultValue(
                    readListMethodInstance.Id, "");
            }
        }
        /// <summary>
        /// Create the specific finder Method, specify the query it will use, and define the input and output parameters associated with it.
        /// The specific finder Method returns exactly one row of data from the data source, given an identifier.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="table"></param>
        /// <param name="lobSystemName"></param>
        /// <param name="catalog"></param>
        /// <param name="entity"></param>
        private static void CreateReadItemMethod(string name, string table, string lobSystemName, List<ExternalColumnReference> referenceList, AdministrationMetadataCatalog catalog, Entity entity)
        {
            uint language = SPContext.Current.Web != null ? SPContext.Current.Web.Language : 1033;

            string itemMethodName = "Get" + name;
            string listMethodEntity = name + "List";
            string itemMethodEntity = name;

            ExternalColumnReference keyColumn = null;

            Method getItemMethod = entity.Methods.Create(itemMethodName, true, false, table);

            // Specify the query
            // "SELECT [CustomerId] , [FirstName] , [LastName] , [Phone] , [EmailAddress] , [CompanyName] FROM [Customers].[SalesLT].[Customer] WHERE [CustomerId] = @CustomerId"
            string querySingleItemString = "SELECT ";
            string whereClause = "";

            foreach (ExternalColumnReference reference in referenceList)
            {
                querySingleItemString += "[" + reference.SourceName + "], ";

                if(reference.IsKey)
                {
                    keyColumn = reference;
                    whereClause = "[" + reference.SourceName + "] = @" + reference.DestinationName;
                }
            }
            querySingleItemString = querySingleItemString.Substring(0, querySingleItemString.Length - 2);
            querySingleItemString += " FROM [" + table + "] WHERE " + whereClause;

            // Set the method properties
            getItemMethod.Properties.Add("RdbCommandText", querySingleItemString);
            getItemMethod.Properties.Add("RdbCommandType", "Text");
            getItemMethod.Properties.Add("BackEndObjectType", "SqlServerTable");
            getItemMethod.Properties.Add("BackEndObject", table);
            getItemMethod.Properties.Add("Schema", "dbo");

            // Create the EntityID input parameter
            if (keyColumn == null)
            {
                var message = SPUtility.GetLocalizedString("$Resources:ExternalLookup_Creator_KeyColumn", "Resources", language);
                throw new NullReferenceException(message);
            }

            string idParameter = "@" + keyColumn.DestinationName;
            Parameter entityIdParameter = getItemMethod.Parameters.Create(idParameter, true, DirectionType.In);

            // Create the TypeDescriptor for the EntityID parameter
            entityIdParameter.CreateRootTypeDescriptor(
                keyColumn.DestinationName,
                true,
                keyColumn.Type,
                keyColumn.SourceName,
                new IdentifierReference(keyColumn.DestinationName, new EntityReference("EFEXCON.ExternalLookup", itemMethodEntity, catalog), catalog),
                null,
                TypeDescriptorFlags.None,
                null,
                catalog);

            // Create the Entity return parameter
            Parameter modelParameter = getItemMethod.Parameters.Create(itemMethodEntity, true, DirectionType.Return);

            // Create the TypeDescriptors for the Entity return parameter
            TypeDescriptor returnRootCollectionTypeDescriptor =
                modelParameter.CreateRootTypeDescriptor(
                    listMethodEntity,
                    true,
                    "System.Data.IDataReader, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    listMethodEntity,
                    null,
                    null,
                    TypeDescriptorFlags.IsCollection,
                    null,
                    catalog);

            TypeDescriptor returnRootElementTypeDescriptor =
                returnRootCollectionTypeDescriptor.ChildTypeDescriptors.Create(
                    itemMethodEntity,
                    true,
                    "System.Data.IDataRecord, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
                    itemMethodEntity,
                    null,
                    null,
                    TypeDescriptorFlags.None,
                    null);

            foreach (ExternalColumnReference reference in referenceList)
            {
                IdentifierReference identityReference = null;

                if (reference.IsKey)
                {
                    identityReference = new IdentifierReference(reference.DestinationName, new EntityReference("EFEXCON.ExternalLookup", itemMethodEntity, catalog), catalog);
                }

                returnRootElementTypeDescriptor.ChildTypeDescriptors.Create(
                    reference.DestinationName,
                    true,
                    reference.Type,
                    reference.SourceName,
                    identityReference,
                    null,
                    TypeDescriptorFlags.None,
                    null
                );
            }

            // Create the specific finder method instance
            getItemMethod.MethodInstances.Create(itemMethodName, true, returnRootElementTypeDescriptor, MethodInstanceType.SpecificFinder, true);
        }