/// <summary> /// Initializes the Catalog /// </summary> private void InitializeMetadataStore() { // Open the shared metadatacatalog cache on the client to // read LOB information. This class represnts the Office // client shared storage for BCS metadata. Once on client, // this metadata can be accessed from any Office application catalog = new RemoteSharedFileBackedMetadataCatalog(); // Get the SalesOrderHeader entity instance using // namespace and name entitySalesOrderHeader = catalog.GetEntity( SalesOrderHeaderNamespace, SalesOrderHeader); // Get the SalesOrderLine entity instance using // namespace and name entitySalesOrderLine = catalog.GetEntity( SalesOrderHeaderNamespace, SalesOrderLine); salesOrderLineEntityIds = entitySalesOrderLine.GetIdentifiers(); // Get the handle to LobSystem lobInstance = catalog.GetLobSystem(SalesOrderLobSystemName). GetLobSystemInstances()[SalesOrderLobSystemInstanceName]; // Create list to hold changed rows changedSalesLineRows = new List <DataRow>(); }
/// <summary> /// Get the instance of a Business Data Connectivity entity /// </summary> /// <param name="site"></param> /// <param name="nameSpace"></param> /// <param name="entityName"></param> /// <param name="entityId"></param> /// <returns></returns> private static IEntityInstance GetEntityInstance(SPSite site, string nameSpace, string entityName, string entityId) { //Use the scope of the currently opened site SPServiceContext ctx = SPServiceContext.GetContext(site); SPServiceContextScope scope = new SPServiceContextScope(ctx); //Get the BDC service of the local SP farm BdcService service = SPFarm.Local.Services.GetValue <BdcService>(); IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog(ctx); IEntity entity = catalog.GetEntity(nameSpace, entityName); ILobSystemInstance LobSysteminstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value; IEntityInstance entInstance = null; //Loop through the methods defined in the LOB foreach (KeyValuePair <string, IMethod> method in entity.GetMethods()) { IMethodInstance methodInstance = method.Value.GetMethodInstances()[method.Key]; //Get the Specific Finder method of the LOB if (methodInstance.MethodInstanceType == MethodInstanceType.SpecificFinder) { //Find the record with the ID from the datasource Microsoft.BusinessData.Runtime.Identity id = new Microsoft.BusinessData.Runtime.Identity(entityId); entInstance = entity.FindSpecific(id, entity.GetLobSystem().GetLobSystemInstances()[0].Value); } } return(entInstance); }
public PartManagementRepository() { bdcService = SPFarm.Local.Services.GetValue <BdcService>(); catalog = bdcService.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current); partsManagementLobSystemInstance = catalog.GetLobSystem(Constants.LobSystemName).GetLobSystemInstances()[Constants.LobSystemName]; contactsLobSystemInstance = catalog.GetLobSystem(Constants.ContactsLobSystemName).GetLobSystemInstances()[Constants.ContactsLobSystemName]; }
/// <summary> /// Gets a LOB system instance from a INamedLobSystemInstanceDictionary object using a key and a specific string comparer to examine the keys. /// </summary> /// <param name="lobInstances">A INamedLobSystemInstanceDictionary object to be searched.</param> /// <param name="key">The key to search for.</param> /// <param name="comparisonType">The string comparer to use to compare the keys.</param> /// <returns>A ILobSystemInstance object that matches the key; otherwise, null.</returns> public static ILobSystemInstance GetByKey(this INamedLobSystemInstanceDictionary lobInstances, string key, StringComparison comparisonType) { ILobSystemInstance lobInstance = null; foreach (string lobInstanceKey in lobInstances.Keys) { if (lobInstanceKey.Equals(key, comparisonType)) { lobInstance = lobInstances[lobInstanceKey]; break; } } return(lobInstance); }
static void ExecuteBcsEctMethods(string siteUrl) { using (SPSite site = new SPSite(siteUrl)) { using (new SPServiceContextScope(SPServiceContext.GetContext(site))) { BdcServiceApplicationProxy proxy = (BdcServiceApplicationProxy)SPServiceContext.Current.GetDefaultProxy(typeof(BdcServiceApplicationProxy)); DatabaseBackedMetadataCatalog model = proxy.GetDatabaseBackedMetadataCatalog(); IEntity entity = model.GetEntity("EmployeeEntityModel.BdcModel1", "Entity1"); // Namespace, Entity name ILobSystemInstance lobSystemInstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value; IMethodInstance method = entity.GetMethodInstance("ReadList", MethodInstanceType.Finder); // Finder method name IView view = entity.GetFinderView(method.Name); IFilterCollection filterCollection = entity.GetDefaultFinderFilters(); IEntityInstanceEnumerator entityInstanceEnumerator = entity.FindFiltered(filterCollection, method.Name, lobSystemInstance, OperationMode.Online); Console.WriteLine("Employee Login ID | Job Title"); while (entityInstanceEnumerator.MoveNext()) { Console.WriteLine(entityInstanceEnumerator.Current["LoginID"].ToString() + " - " + entityInstanceEnumerator.Current["JobTitle"].ToString()); // Column names } Console.ReadLine(); } } }
private static IEntityInstance GetEntityInstance(SPBusinessDataField dataField, string entityId, SPSite site, SPListItem item, string finderMethodName) { IEntityInstance entInstance = null; try { IEntity entity = GetEntity(site, dataField); ILobSystemInstance lobSystemInstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value; // Get methods collection foreach (KeyValuePair <string, IMethod> method in entity.GetMethods()) { // Get current method's instance IMethodInstance methodInstance = method.Value.GetMethodInstances()[method.Key]; // Execute specific finder method if (methodInstance.MethodInstanceType == MethodInstanceType.SpecificFinder && methodInstance.Name == finderMethodName) { Identity id = null; if (EntityInstanceIdEncoder.IsEncodedIdentifier(entityId)) { object[] oIDList = EntityInstanceIdEncoder.DecodeEntityInstanceId(entityId); id = new Identity(oIDList[0]); // Execute specific finder method and get the entity instance entInstance = entity.FindSpecific(id, methodInstance.Name, entity.GetLobSystem().GetLobSystemInstances()[0].Value); item[dataField.RelatedField] = entityId.ToString(); } else { object oID = GetTypedIDValue(entityId, entity); id = new Identity(oID); string encodedIdentifier = EntityInstanceIdEncoder.EncodeEntityInstanceId(new object[] { oID }); // Execute specific finder method and get the entity instance entInstance = entity.FindSpecific(id, methodInstance.Name, entity.GetLobSystem().GetLobSystemInstances()[0].Value); item[dataField.RelatedField] = encodedIdentifier; } } } } catch (ObjectNotFoundException notFoundException) { LogError("GetEntityInstance errored with message " + notFoundException.Message + ". Adding item to Guidewire."); Console.WriteLine("GetEntityInstance errored with message " + notFoundException.Message + ". Adding item to Guidewire."); bool addDocumentToGuidewire = CallGuidewire(item, GuidewireOperationType.New); string outMessage = ""; if (addDocumentToGuidewire) { outMessage = string.Format("Item with ID {0} added to Guidewire", item.ID); } else { outMessage = string.Format("Item with ID {0} could not be added to Guidewire", item.ID); if (Settings.Default.DeleteFailures) { try { // Recycle the item if it can't be added to guidewire and it's older than 30 days if (DateTime.Now.AddDays(-30) > (DateTime)item[SPBuiltInFieldId.Modified]) { item.Recycle(); } } catch { // Swallow this error. The item doesn't exist in Guidewire and can't be deleted in SharePoint. It has problems } } LogError(outMessage); } Console.WriteLine(outMessage); } catch (Exception ex) { // Swallow this error LogError("GetEntityInstance errored with message " + ex.Message); Console.WriteLine("GetEntityInstance errored with message " + ex.Message); } return(entInstance); }
protected void CreateNewCustomer_Click(object sender, EventArgs e) { // Make sure we have values for the entity namespace and name. if (!EntityValuesAreSet) { DisplaySetPropertyValuePrompt(true); return; } else { DisplaySetPropertyValuePrompt(false); } try { using (new Microsoft.SharePoint.SPServiceContextScope( SPServiceContext.GetContext(SPContext.Current.Site))) { // Get the BDC service and metadata catalog. BdcService service = SPFarm.Local.Services.GetValue <BdcService>(String.Empty); IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog( SPServiceContext.Current); // Get the entity using the specified name and namespace. IEntity entity = catalog.GetEntity(EntityNamespace, EntityName); ILobSystemInstance LobSysteminstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value; // Get the fields on the entity. IView createView = entity.GetCreatorView("CreateCustomer"); IFieldValueDictionary valueDictionary = createView.GetDefaultValues(); // Set the values of the entity fields. valueDictionary["EmailAddress"] = Email.Text; valueDictionary["FirstName"] = FirstName.Text; valueDictionary["LastName"] = LastName.Text; valueDictionary["MiddleName"] = MiddleName.Text; valueDictionary["Phone"] = Phone.Text; valueDictionary["Title"] = Title.Text; // Call the creator method and display the returned // Customer ID. Identity id = entity.Create(valueDictionary, LobSysteminstance); CustomerID.Text = id.GetIdentifierValues().GetValue(0).ToString(); StatusLabel.ForeColor = Color.Green; StatusLabel.Text = "Customer successfully created."; } } catch (Exception ex) { StatusLabel.ForeColor = Color.Red; StatusLabel.Text = "Unable to create customer." + ex.Message; } }
protected void UpdateCustomer_Click(object sender, EventArgs e) { // Make sure we have values for the entity namespace and name. if (!EntityValuesAreSet) { DisplaySetPropertyValuePrompt(true); return; } else { DisplaySetPropertyValuePrompt(false); } // Do simple validation of the customer ID. Make sure it is // an integer. int customerID = -1; if (!ValidateCustomerID(CustomerID.Text, ref customerID)) { StatusLabel.ForeColor = Color.Red; StatusLabel.Text = "Please enter an integer for the Customer ID value."; return; } try { using (new Microsoft.SharePoint.SPServiceContextScope( SPServiceContext.GetContext(SPContext.Current.Site))) { // Get the BDC service and metadata catalog. BdcService service = SPFarm.Local.Services.GetValue <BdcService>(String.Empty); IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog( SPServiceContext.Current); // Get the entity using the specified name and namespace. IEntity entity = catalog.GetEntity(EntityNamespace, EntityName); ILobSystemInstance LobSysteminstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value; // Create an Identity based on the specified Customer ID. Identity identity = new Identity(customerID); // Get a method instance for the Updater method. IMethodInstance method = entity.GetMethodInstance("UpdateCustomer", MethodInstanceType.Updater); // The UpdateCustomer method of the external content type // maps to the UpdateCustomer method in the AdventureWorks // web service. Looking at the source for the web service // shows that the UpdateCustomer method has the following // signature: // // public void UpdateCustomer(SalesCustomer customer) // // The SalesCustomer type has the following layout: // // public class SalesCustomer // { // public int CustomerId { get; set; } // public String Title { get; set; } // public String FirstName { get; set; } // public String MiddleName { get; set; } // public String LastName { get; set; } // public String EmailAddress { get; set; } // public String Phone { get; set; } // public DateTime ModifiedDate { get; set; } // } // Get the collection of parameters for the method. // In this case there is only one. IParameterCollection parameters = method.GetMethod().GetParameters(); // Use type reflection to get an instance of a // SalesCustomer object to pass as a parameter. ITypeReflector reflector = parameters[0].TypeReflector; ITypeDescriptor rootTypeDescriptor = parameters[0].GetRootTypeDescriptor(); object[] methodParamInstances = method.GetMethod().CreateDefaultParameterInstances( method); Object instance = methodParamInstances[0]; // Get type descriptors for each of the SalesCustomer // members. ITypeDescriptor customerIDTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[0]; ITypeDescriptor titleTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[1]; ITypeDescriptor firstNameTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[2]; ITypeDescriptor middleNameTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[3]; ITypeDescriptor lastNameTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[4]; ITypeDescriptor emailAddressTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[5]; ITypeDescriptor phoneTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[6]; ITypeDescriptor modifiedDateTypeDescriptor = rootTypeDescriptor.GetChildTypeDescriptors()[7]; // Set the values of the SalesCustomer object members // with the values specified by the user. reflector.Set(customerIDTypeDescriptor, rootTypeDescriptor, ref instance, customerID); reflector.Set(titleTypeDescriptor, rootTypeDescriptor, ref instance, Title.Text); reflector.Set(firstNameTypeDescriptor, rootTypeDescriptor, ref instance, FirstName.Text); reflector.Set(middleNameTypeDescriptor, rootTypeDescriptor, ref instance, MiddleName.Text); reflector.Set(lastNameTypeDescriptor, rootTypeDescriptor, ref instance, LastName.Text); reflector.Set(emailAddressTypeDescriptor, rootTypeDescriptor, ref instance, Email.Text); reflector.Set(phoneTypeDescriptor, rootTypeDescriptor, ref instance, Phone.Text); reflector.Set(modifiedDateTypeDescriptor, rootTypeDescriptor, ref instance, DateTime.Now); // Execute the updater method, passing the parameter. entity.Execute(method, LobSysteminstance, ref methodParamInstances); StatusLabel.ForeColor = Color.Green; StatusLabel.Text = "Customer successfully updated."; } } catch (Exception ex) { StatusLabel.ForeColor = Color.Red; StatusLabel.Text = "Unable to find customer with ID = " + CustomerID.Text + ". " + ex.Message; } }
protected void FindCustomerByID_Click( object sender, EventArgs e) { // Make sure we have values for the entity namespace and name. if (!EntityValuesAreSet) { DisplaySetPropertyValuePrompt(true); return; } else { DisplaySetPropertyValuePrompt(false); } // Do simple validation of the customer ID. Make sure it is // an integer. int customerID = -1; if (!ValidateCustomerID(CustomerID.Text, ref customerID)) { ClearFields(false); StatusLabel.ForeColor = Color.Red; StatusLabel.Text = "Please enter an integer for the Customer ID value."; return; } try { using (new Microsoft.SharePoint.SPServiceContextScope( SPServiceContext.GetContext(SPContext.Current.Site))) { // Get the BDC service and metadata catalog. BdcService service = SPFarm.Local.Services.GetValue <BdcService>(String.Empty); IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog( SPServiceContext.Current); // Get the entity using the specified name and namespace. IEntity entity = catalog.GetEntity(EntityNamespace, EntityName); ILobSystemInstance LobSysteminstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value; // Create an Identity based on the specified Customer ID. Identity identity = new Identity(customerID); // Get a method instance for the SpecificFinder method. IMethodInstance method = entity.GetMethodInstance("GetCustomerById", MethodInstanceType.SpecificFinder); // Execute the Specific Finder method to return the // customer data. IEntityInstance iei = entity.FindSpecific(identity, LobSysteminstance); // Display the data for the returned customer in the UI. Title.Text = iei["Title"] != null ? iei["Title"].ToString() : string.Empty; FirstName.Text = iei["FirstName"] != null ? iei["FirstName"].ToString() : string.Empty; MiddleName.Text = iei["MiddleName"] != null ? iei["MiddleName"].ToString() : string.Empty; LastName.Text = iei["LastName"] != null ? iei["LastName"].ToString() : string.Empty; Email.Text = iei["EmailAddress"] != null ? iei["EmailAddress"].ToString() : string.Empty; Phone.Text = iei["Phone"] != null ? iei["Phone"].ToString() : string.Empty; } } catch (Exception ex) { ClearFields(false); StatusLabel.ForeColor = Color.Red; StatusLabel.Text = "Unable to find customer with ID = " + CustomerID.Text + ". " + ex.Message; } }
public void ExecuteStatic(IMethodInstance methodInstance, ILobSystemInstance lobSystemInstance, object[] methodSignatureArgs, IExecutionContext context) { if (methodInstance == null) { throw (new ArgumentNullException("methodInstance")); } if (lobSystemInstance == null) { throw (new ArgumentNullException("lobSystemInstance")); } if (methodSignatureArgs == null) { throw (new ArgumentNullException("args")); } #region validate the base folder object baseFolderValue; if (!lobSystemInstance.GetProperties().TryGetValue(baseFolderPropertyName, out baseFolderValue)) { throw new InvalidOperationException("BaseFolder property is missing"); } String baseFolderName = baseFolderValue as string; if (String.IsNullOrEmpty(baseFolderName)) { throw new InvalidOperationException("BaseFolder proeprty contains an invalid value."); } DirectoryInfo baseFolder = new DirectoryInfo(baseFolderName); if (!baseFolder.Exists) { throw new InvalidOperationException("Base folder doesn't exist."); } #endregion //This connector works based on the type of the MethodInstance //Most other connectors work on the name of the method if (methodInstance.MethodInstanceType == MethodInstanceType.Finder) { //Connector assumption: //First parameter will always be a wildcarded search string for file name //Second parameter will always be the return value String wildcard = methodSignatureArgs[0] as string; IList <FileInfo> results = new List <FileInfo>(); methodSignatureArgs[1] = baseFolder.GetFiles(wildcard); } else if (methodInstance.MethodInstanceType == MethodInstanceType.SpecificFinder) { //Connector assumption: //First parameter will always be the file name //Second parameter will always be the return value string fileName = methodSignatureArgs[0] as string; FileInfo result = new FileInfo(Path.Combine(baseFolder.FullName, fileName)); if (result.Exists && result.Directory.FullName.Equals(baseFolder.FullName)) { methodSignatureArgs[1] = result; } } else if (methodInstance.MethodInstanceType == MethodInstanceType.StreamAccessor) { //Connector assumption: //First parameter will always be the file name //Second parameter will always be the return value string fileName = methodSignatureArgs[0] as string; FileInfo result = new FileInfo(Path.Combine(baseFolder.FullName, fileName)); if (result.Exists && result.Directory.FullName.Equals(baseFolder.FullName)) { methodSignatureArgs[1] = result.OpenRead(); } } }
public Uri GetDisplayUri(ILobSystemInstance lobSystemInstance) { throw new NotImplementedException(); }
public Uri GetDisplayUri(IEntity entity, ILobSystemInstance lobSystemInstance) { return(this.accessUri); }
public Uri GetAccessUri(IEntity entity, ILobSystemInstance lobSystemInstance) { throw new NotImplementedException(); }
/// <summary> /// Generates display URL for a LobSystemInstance. /// </summary> public Uri GetDisplayUri(ILobSystemInstance lobSystemInstance) { throw new NotImplementedException(); }
/// <summary> /// Generates access URL for an Entity. /// </summary> public Uri GetAccessUri(IEntity entity, ILobSystemInstance lobSystemInstance) { throw new NotImplementedException(); }
/// <summary> /// This method does the processing of incoming URLs. The intent here is to receive a URL via this context /// object, parse it to determine what metadata object it refers to, and then populate members of this class /// with this information. /// </summary> /// <param name="context"> /// Supplies the connection context. The context contains (most importantly) the URL of the item being crawled, /// and also other information about the current crawl. /// </param> public override void Initialize( Microsoft.Office.Server.Search.Connector.IConnectionContext context) { Uri sourceUri = context.Path; // // A URL can point to a LobSystem, a LobSystemInstance, an Entity, or a specific instance of an Entity. // A specific instance of an Entity for MyFileConnector would be, of course, an actual file or folder on // disk. The other BCS metadata objects exist to provide you more flexibility in designing your connector // by providing slightly different crawling behaviors (which we'll detail below). // // Your job in this method is to parse the URL and decide what it's pointing to. Then, populate the // appropriate class members to indicate what it's pointing to. // // To indicate that the supplied URL refers to a(n): Populate only these class members: // // LobSystem this.LobSystem // // LobSystemInstance this.LobSystem // this.LobSystemInstance // // Entity this.LobSystem // this.LobSystemInstance // this.Entity // // Entity instance this.LobSystem // this.LobSystemInstance // this.Entity // this.Identity // // What happens when these BCS metadata objects are crawled? Obviously, if you've got an entity instance, // you're crawling an actual item in your repository. But what about the others? In general, there's no real // data or metadata associated with any of them until you get down to an actual Entity instance (i.e., a // file or folder on disk, in the case of this connector). So the only real thing that happens when these // objects are crawled is that they emit their children, which will then subsequently be crawled. So here's // what the "children" of each of these metadata objects are: // // Metadata object type Children that are emitted when crawled // // LobSystem All LobSystemInstances in the model file that are marked with the // 'ShowInSearchUI' property. // // LobSystemInstance If at least one Entity defined in this LobSystemInstance has a Finder method // with the 'RootFinder' property set, the LobSystemInstance will emit all Entities // that have Finder methods marked with the 'RootFinder' property. If an Entity // does not have a RootFinder, it will not be emitted. // // If no Entities in the LobSystemInstance with a Finder marked with the // 'RootFinder' property, the LobSystemInstance will emit any Entities that have // both IdEnumerator and SpecificFinder methods defined in the model file. Note: If // you define only one of the two (either IdEnumerator or SpecificFinder) in this // case, an exception will be thrown at crawl time. You must define both to be // crawled in this manner. // // (Up to this point, with the previous two metadata objects, we had not yet called into the custom // connector shim. Instead, we were able to figure out what to emit from the model file alone. Starting with // the Entity, we will be calling into the custom connector shim, and also the full and incremental crawl // behavior can be different...) // // Metadata object type Children that are emitted when crawled // // Entity Full crawl: // If the Entity has a Finder with the 'RootFinder' property set, that method is // called. Whatever entity instances your shim emits are the child items of the // Entity. If there is no Finder with the 'RootFinder' property set, but there // is an IdEnumerator defined for the entity, that method will be called, and // whatever entity instances your shim emits are the child items of the Entity. // // Incremental crawl: // If the Entity is the source for any AssociationNavigator methods that are marked // with the 'DirectoryLink' property, the behavior is the same as in the full // crawl. If there are no AssociationNavigator methods where the Entity is the // source, marked with the 'DirectoryLink' property, and the Entity has both a // ChangedIdEnumerator and DeletedIdEnumerator defined, then both of those methods // will be called in an incremental crawl. If none of the above is true, the // incremental crawl behavior is the same as full crawl. // // (Now, for an actual Entity instance (e.g., a file or folder on disk, in this case), it will be helpful to // define the concept of 'container'-type Entities. A 'container' type Entity is an Entity that is defined // in your model file as the SourceEntity of any AssociationNavigator marked with the 'DirectoryLink' // property.) // // Metadata object type Children that are emitted when crawled // // Container-type Full crawl: // Entity instance The association navigators for which the Entity type is the SourceEntity are // called. // // Incremental crawl: // This is the same as in a full crawl, unless several things are configured to // enable your shim to more intelligently decide what to emit. Here's what needs // to be configured to enable this behavior: // // 1. The SpecificFinder of the Entity has to return a field containing the number // of deleted direct child items in that particular container and this field // must be identified in the model file by defining the 'DeletedCountField' // property on the SpecificFinder method instance, where its value must be the // name of the field that returns the delete count. // // 2. The AssociationNavigator for which this Entity is the SourceEntity must // include in its return type descriptor a last modified time DateTime field // and this field must be identified in the model file by defining the // 'LastModifiedTimeStamp' property on the AssociationNavigator method // instance, where its value must be the name of the fiels that returns the // last modified DateTime. // // 3. The AssociationNavigator for which this Entity is the SourceEntity must // have an input filter defined, and that input filter must have the // 'CrawlStartTime' string property defined: // // <FilterDescriptor Name="LastModifiedFilter" Type="Input"> // <Properties> // <Property Name="CrawlStartTime" Type="String">x</Property> // </Properties> // </FilterDescriptor> // // 4. The AssociationNavigator for this this Entity is the SourceEntity must // take a DateTime input parameter, and that parameter must be associated with // the filter described in #3: // // <Parameter Name="lastModifiedTime" Direction="In"> // <TypeDescriptor // Name="lastModifiedTime" // TypeName="System.DateTime" // AssociatedFilter="LastModifiedFilter" /> // </Parameter> // // If this is the case, then the association navigator is called, and your shim // will be provided the last modified time to determine what items to return. // // Non-container-type Full and incremental crawl behavior is the same. The SpecificFinder of the // Entity instance non-container Entity is called. You can also enable caching behavior, if the // method that emitted this Entity instance has the 'UseClientCachingForSearch' // property defined on its method instance. If caching is enabled in this way, // the SpecificFinder is not called, and only the data returned by the method // that originally emitted this Entity instance (i.e., an AssociationNavigator // or IdEnumerator, etc.) will be used to index the item. Note: If you return a // security descriptor in the return type descriptor, identified by the // 'WindowsSecurityDescriptorField' defined on the method instance, then items // will *not* be cached, regardless of if you set the 'UseClientCachingForSearch' // property or not. The reason is that the SharePoint Search crawler has a limited // size for caching an individual item, and security descriptors can regularly // exceed that size. // // // As we mentioned above, we expect that every URL will resolve to a valid folder or file once we // translate it. Because of this, we won't really need to crawl any of the BCS metadata objects (LobSystem, // LobSystemInstance or Entity) - we'll only be crawling Entity instances. So based on the above, we know // that this method must end up populating all four LobUri properties. // // // We already populated this.lobSystem in the constructor. Now here's this.lobSystemInstance. // LobSystemInstances are statically defined in your model file. In this sample, we've only defined one. // this.lobSystemInstance = this.lobSystem.GetLobSystemInstances()[0].Value; // // Next, we need to figure out what Entity to which the URL refers to populate this.Entity. So for starters, // let's read the first segment to see what entity type we should assign to this.Entity. // String entityType = sourceUri.Segments[1].Replace("/", ""); if(entityType.Equals("MyFolder", StringComparison.OrdinalIgnoreCase)) { this.entity = this.Catalog.GetEntity("MyFileConnector", "MyFolder"); } else if (entityType.Equals("MyFile", StringComparison.OrdinalIgnoreCase)) { this.entity = this.Catalog.GetEntity("MyFileConnector", "MyFile"); } else { throw new Microsoft.BusinessData.Runtime.RuntimeException(String.Format( "Invalid entity type {0} specified in URL {1}", entityType, sourceUri.ToString())); } // // Finally, populate this.identity. Generally, the 'identity' is whatever your repository needs to uniquely // identify an Entity instance. In the case of our repository, an NTFS file system, that would conveniently // just be the path to the file. So reconstruct the URL as a UNC path, minus the first segment. // StringBuilder path = new StringBuilder(@"\\"); path.Append(sourceUri.Host); path.Append(@"\"); for (int i = 2; i < sourceUri.Segments.Length; ++i) { path.Append(SPHttpUtility.UrlPathDecode(sourceUri.Segments[i].Replace('/', '\\'), false)); } this.identity = new Microsoft.BusinessData.Runtime.Identity(path.ToString()); }