Data Explorer Integration

Once a BDP provider has been written, there is one last step to get the provider to act as a first-class citizen in the BDP framework. By following these steps, the provider will be able to participate fully in the Data Explorer - including viewing/updating of data, adhoc querying of data, and drag and drop functionality to create BDP components within the IDE.

DataSource Configuration

There are 2 xml files that control the configuration for Borland Data Providers. All providers are listed in BdpDataSources.xml. Each provider in that file describes the capabilities that it can use from within the Data Explorer. A sample BdpDataSources.xml file might look like this:

<?xml version="1.0" standalone="yes"?>
<DataSource xmlns="http://www.borland.com/schemas/bds/1.0/bdpdatasources.xsd">
  <provider name="Interbase" connectionStringType="Borland.Data.Interbase.IBConnectionString,  Borland.Data.Interbase, Version=1.1.0.0, Culture=neutral, PublicKeyToken=91d62ebb5b0d1b1b">
    <objectTypes>
      <objectType>Tables
      <objectType>Procedures
      <objectType>Views
    </objectTypes>
  </provider>
  <provider name="Oracle" connectionStringType="Borland.Data.Oracle.OracleConnectionString, Borland.Data.Oracle, Version=1.1.0.0, Culture=neutral, PublicKeyToken=91d62ebb5b0d1b1b">
    <objectTypes>
      <objectType>Tables
      <objectType>Procedures
      <objectType>Views
      <objectType>Functions
      <objectType>Synonyms
    </objectTypes>
  </provider>
</DataSource>
In order to get a custom provider registered with BDP, you must add a entry to the BdpDataSources.xml file.

Reading BdpDataSources.xml

Most people will only need to query information from this XML file using the Borland.Data.Schema.ISQLDataSource interface. There is a standard implementation of this interface in Borland.Data.Design.BdpDataSource. The ISQLDataSource interface is defined as:

public interface ISQLDataSource
{
  String[] GetProviders ();
  String[] GetConnections (String ProviderName);
  String[] GetDbObjectTypes (String ProviderName);
}
The GetProviders() method returns a list of providers in the BdpDataSources.xml file. The GetDbObjectTypes() method returns a list of supported capabilities ( elements) for a given provider in the BdpDataSources.xml file. And finally, the GetConnections() method returns a list of connections defined for the provider. This list of connections comes from the BdpConnections.xml file, which will be discussed next. The supported elements that Data Explorer will use are:
  • Tables
  • Views
  • Procedures
  • Functions
  • Synonyms
When the Data Explorer builds up the information to view, only the nodes that are present will be used in the display.

BdpConnectionString

The element shown in the above BdpDataSources.xml contains an attribute called "connectionStringType". This points to a fully qualified class that descends from Borland.Data.Common.BdpConnectionString. If your database has specific properties that need to be set, you will define them in this class. Be sure to use the Category attribute to classify your properties into an appropriate classification. The 3 default classifications are: "Connection", "Options", and "Provider Settings". A provider-specific BdpConnectionString object will look something like this:
/// 
/// InterBase specific connection string
/// 
public class IBConnectionString : BdpConnectionString
{
  // Property Names
  protected const string SRoleName = "RoleName";
  // Property Values
  new protected const string SProvider = "InterBase";
  protected const string AssemblyName = "Borland.Data.InterBase,Version=1.1.0.0,Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b";
  protected const string VendorClientName = "gds32.dll";
  protected const string DefRoleName = "myrole";
  // Other InterBase-specific property names and values go here...

  public IBConnectionString() : base()
  {
    SetProvider(SProvider);
    RoleName = DefRoleName;
    DefaultAssembly = AssemblyName;
    DefaultVendorClient = VendorClientName;
  }


  [Category(OptionsCat)]
  [DefaultValue(DefRoleName)]
  public string RoleName
  {
    get
    {
      return OptionsDictionary[SRoleName];
    }
    set
    {
      OptionsDictionary[SRoleName] = value;
    }
  }
}

Connection Configuration

Information about a named connection is kept in the BdpConnections.xml file. Data from the appropriate BdpConnectionString is used to read and write the XML nodes in this connection string. A sample entry for a connection would look like this:


  gds32.dll
  Borland.Data.Interbase,Version=1.1.0.0,Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b
  IBLocal
  localhost:c:/program files/borland/interbase/examples/database/employee.gdb
  sysdba
  masterkey

Developers may want to use the Borland.Data.Design.BdpConnectionManager class. This static class provides a wrapper to manage the BdpConnections.xml file easily. The class definition looks like this:

public class BdpConnectionManager()
{
  public static ISQLDataSource DataSource
  // method to write data out to the BdpConnections.xml file
  public static void Flush()
  // method to create a new BdpConnectionString for a provider
  public static BdpConnectionString NewConnectionString(string connectionName, string providerName)
  // method to add a connection
  public static int AddNewConnection(string connectionName, string providerName)
  // method to delete a connection
  public static void DeleteConnection(string connectionName)
  // method to rename a connection
  public static void RenameConnection(string oldName, string newName)
  // method to test the validity of a connection
  public static bool TestConnection(IServiceProvider serviceProvider, BdpConnectionString connectionString)
  // method to retrieve the ConnectionString for a give connection
  public static BdpConnectionString GetConnectionString(string connectionName)
  // methods to set properties for a given connection
  public static void AssignConnectionProps(BdpConnection connection, BdpConnectionString connectionString)
  public static void AssignConnectionProps(BdpConnection connection, int connectionStringIndex)
  public static void AssignConnectionProps(BdpConnection connection, string connectionName)
  // method to return the index of the specified connectionString
  public static int IndexOfConnectionName(string connectionName)
  public static int IndexOfConnectionProps(BdpConnection connection)
  // ISQLDataSource implementation methods
  public static string[] GetConnectionNames(string providerName)
  public static string[] GetProviderNames()
  public static string[] GetDbObjectTypes(string providerName)
  public static Type[] GetProviderConnStrTypes()
  public static BdpDataProvider[] DataProviders
  //  retrieve all ConnectionStrings in the file
  public static BdpConnectionStringCollection ConnectionStrings
}

Custom DataSource Implementation

If the default BdpDataSource class does not do everything you need, you can provide your own implementation. Simply create a class that implements ISQLDataSource and put it in a DLL assembly. Then, register the assembly by adding the following registry key:

[HKEY_CURRENT_USER\Software\Borland\BDS\1.0\BorlandDataExplorer] "CustomAssembly"="c:/dev/dotnet/CustomDS.dll"

You should call the default BdpDataSource implementation and modify the results before returning the value from the function. If you don't do this, you will completely replace the list of providers and interfere with providers that are properly registered.

ISQLResolver

The interface Borland.Data.Schema.ISQLResolver needs to be implemented for your provider in order to have SQL generation capibilities. This interface is called from a variety of places when SQL is needed. For example, the CommandText editor and BdpCommandBuilder both rely on a proper implementation of ISQLResolver to generate the correct SQL.
  public interface ISQLResolver
  {
     // The character(s) used to Quote database object names
     String QuotePrefix { get; set;}
     String QuoteSuffix { get; set;}
     // A list of column names that should be excluded from updating
     String[] ReadOnly { get; set;}
     // A list of column names that should not be used in the WHERE clause
     String[] ExcludeFilter   { get; set;}
     // The current DataRow
     DataRow Row { get; set; }

     String GetInsertSQL(IDbConnection Conn, IDbCommand Command,
         DataRowCollection columns, String TableName);
     String GetUpdateSQL(IDbConnection Conn, IDbCommand Command,
         DataRowCollection columns, String TableName, BdpUpdateMode UpdateMode);
     String GetDeleteSQL(IDbConnection Conn, IDbCommand Command,
         DataRowCollection columns, String TableName, BdpUpdateMode UpdateMode);
     String GetSelectSQL(IDbConnection Conn, DataRowCollection columns,
         String TableName);
  }