dotConnect Universal Documentation
In This Topic
    dotConnect Universal and Arbitrary Data Providers
    In This Topic

    dotConnect Universal supports most of popular database servers and set of data providers, which are enumerated at Supported Providers article. Due to dotConnect Universal open architecture it is possible to use any other ADO.NET data provider with minimum efforts.

    There are two ways of how you can employ arbitrary data provider. First, you can configure it through UniProvider component. This way is easier but has some restrictions. Second, you can implement IUniProvider interface.

    Using UniProvider component

    It is a very easy way to support a data provider. You should only create new UniProvider component and set provider name, assembly and namespace. UniProvider Wizard helps you to link the component to any ADO.NET provider installed at your computer. When component is set up, it can be used by UniConnection in the same way as other providers.

    Although in most cases this way is quite applicable, it has some restrictions such as:


    Sample of using UniProvider component for SQL Server:

    private void UniProviderComp_Click(object sender, System.EventArgs e) {
      
      UniProvider provider = new UniProvider();
      provider.ProviderName = "MS SQL"; 
      provider.AssemblyName = "System.Data";
      provider.Namespace = "System.Data.SqlClient";
      provider.ParameterPlaceholder = '@';
      provider.AllowUnnamedParameters = false;
      UniConnection connection = new UniConnection("Provider=MS SQL;Data Source=server;user id=sa;database=test");
      UniCommand cmd = new  UniCommand("select * from emp", connection);
      try {
        connection.Open();
        UniDataReader rd = cmd.ExecuteReader();
        try {
          while (rd.Read()) {
            MessageBox.Show(rd.GetValue(0).ToString());
          }
        }
        finally {
          rd.Close();
        }
      }
      finally {
        connection.Close();
      }
    
    }
    
    
    Private Sub btUniProviderComp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btUniProviderComp.Click
      Dim provider As UniProvider = New UniProvider
      provider.ProviderName = "MS SQL"
      provider.AssemblyName = "System.Data"
      provider.Namespace = "System.Data.SqlClient"
      provider.ParameterPlaceholder = "@"
      provider.AllowUnnamedParameters = False
      Dim connection As UniConnection = New UniConnection("Provider=MS SQL;Data Source=server;user id=sa;database=test")
      Dim cmd As UniCommand = New UniCommand("select * from emp", connection)
      Try
        connection.Open()
        Dim rd As UniDataReader = cmd.ExecuteReader()
        Try
          While rd.Read()
            MessageBox.Show(rd.GetValue(0).ToString())
          End While
        Finally
          rd.Close()
        End Try
      Finally
        connection.Close()
      End Try
    End Sub
    
    

    Implementing IUniProvider interface

    The another way is to implement IUniProvider interface and register this object at the Provider Manager. It is more universal and efficient solution, though more complex to implement. You can use it if your provider doesn't meet restrctions of using UniProvider component or you need more functionality.

    ProviderName property of IUniProvider interface must return name of the provider. The name is used at the connection to choose used provider. For example, if you specify ProviderName as "MS SQL" you will use connection string like this:

    "Provider = MS SQL; ..."

    The most important in IUniProvider interface methods such as CreateConnection, CreateCommand, CreateDataAdapter, CreateCommandBuilder are needed to create ADO.NET core objects of specified data provider. GetConnectionParameters method provides information about connection string parameter that will be used by ConnectionString editor at design-time.

    Once you implement the IUniProvider interface you need to register your class with ProviderManager.Register method for using in dotConnect Universal.

    If you have problems implementing the IUniProvider interface, contact the Devart support team.

    Here is an example of IUniProvider interface implementation for the Firebird provider for Firebird 2.5 and 3.0. The provider itself can be downloaded from https://www.firebirdsql.org/en/additional-downloads/

    using Devart.Common;
    using Devart.Data.Universal;
    using FirebirdSql.Data.FirebirdClient;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Common;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1 {
    
      // =========================================================================
      // An example of IUniProvider interface implementation for .NET Data Provider for Firebird 3
      // MyFirebirdProvider - is a wrapper for Firebird ADO.NET Data Provider
    
      public class MyFirebirdProvider : IUniProvider {
    
        private string assemblyVersion = "Not available";
    
        public MyFirebirdProvider() {
        }
    
        public string ProviderName {
          get {
            return "MyFirebirdClient";
          }
        }
    
        public string ProviderPrefix {
          get {
            return "FB";
          }
        }
    
        public char ParameterPlaceholder {
          get {
            return '@';
          }
        }
    
        public bool AllowUnnamedParameters {
          get {
            return false;
          }
        }
    
        public bool PortSupported {
          get {
            return true;
          }
        }
    
        public bool DatabaseSupported {
          get {
            return true;
          }
        }
    
        public string WebAssemblyName {
          get {
            return "System.Web";
          }
        }
    
        public string ProviderAssemblyVersion {
          get {
            return assemblyVersion;
          }
        }
    
        public string ProviderDescription {
          get {
            return "Firebird ADO.NET Data Provider";
          }
        }
    
        public  DbProviderFactory GetProviderFactory() {
    
          return FirebirdClientFactory.Instance;
        }
    
        public System.Data.Common.RowUpdatingEventArgs CreateRowUpdatingEventArgs(System.Data.Common.RowUpdatingEventArgs e) {
    
          return new FbRowUpdatingEventArgs(e.Row, e.Command, e.StatementType, e.TableMapping);
        }
    
        public IDbConnection CreateConnection() {
    
          IDbConnection connection = new FbConnection();
          assemblyVersion = connection.GetType().Assembly.GetName().Version.ToString();
          return connection;
        }
    
        public IDbCommand CreateCommand() {
    
          return new FbCommand();
        }
    
        public IDbDataAdapter CreateDataAdapter() {
    
          return new FbDataAdapter();
        }
    
        public IUniCommandBuilder CreateCommandBuilder() {
    
          return new FbCommandBuilderWrapper();
        }
    
        public void DeriveParameters(IDbCommand command) {
    
          FbCommand fbCommand = command as FbCommand;
          FbCommandBuilder.DeriveParameters(fbCommand);
        }
    
        // sets the native type for FbParameter, corresponding to UniDbType
        public void SetNativeDbType(IDbDataParameter nativeParameter, UniDbType uniDbType) {
    
          FbParameter fbParameter = nativeParameter as FbParameter;
    
          if (fbParameter != null)
            fbParameter.FbDbType = FirebirdTypeMapping.GetSpecificType(uniDbType);
        }
    
        // get  uni db type corresponding native db type
        public UniDbType GetUniDbType(IDbDataParameter nativeParameter) {
    
          FbParameter fbParameter = nativeParameter as FbParameter;
    
          if (fbParameter != null)
            return FirebirdTypeMapping.GetUniDbType(fbParameter.FbDbType);
          else
            throw new ArgumentException("nativeParameter");
        }
    
        // convert native provider value to uni value
        public object ConvertProviderValue(UniConnection connection, object value, IDbDataParameter nativeParameter) {
    
          return value;
        }
    
        // convert uni value to native provider value
        public object ConvertUniValue(object value) {
    
          return value;
        }
    
        // is used by UniDataReader for getting provider-specific data
        public object GetProviderSpecificValue(IDataReader nativeReader, int i) {
    
          FbDataReader fbReader = nativeReader as FbDataReader;
    
          if (fbReader != null)
            return fbReader.GetValue(i);
          else
            throw new ArgumentException("nativeReader");
        }
    
        // allows modifying sql taking into consideration provider peculiarities 
        // allows using Uni macros
        public string FormatSql(string sql, IDbConnection innerConnection, UniMacroCollection userMacros) {
    
          return sql;
        }
    
        // some interface methods, used mostly by Uni components,
        // can be implemented explicitly,
        // this will allow keeping clear the provider's public interface visible to the user
        #region explicity implement interface
    
        object IUniProvider.CreateConnectionStringBuilder() {
    
          return new FbConnectionStringBuilder();
        }
    
        // it is necessary to switch pooling off for the native provider, to avoid duplication with
        // Uni pooling
        void IUniProvider.DisablePooling(IDbConnection nativeConnection) {
    
          FbConnectionStringBuilder csb = new FbConnectionStringBuilder();
          csb.ConnectionString = nativeConnection.ConnectionString;
    
          try {
            csb.Pooling = false;
            nativeConnection.ConnectionString = csb.ToString();
          }
          catch {
          }
        }
    
        // required for design-time
        private static UniPropertyDescriptorCollection connectionPropertyDescriptors = null;
    
        UniPropertyDescriptorCollection IUniProvider.GetConnectionStringPropertyDescriptors(ref string refreshKeyword, object refreshKeywordValue) {
    
          if (connectionPropertyDescriptors == null) {
    
            UniPropertyDescriptorCollection descs = new UniPropertyDescriptorCollection();
            descs.Add(new UniPropertyDescriptor("Charset", "Misc", "", typeof(System.String), null, null, 
                "Devart.Data.Universal.CharsetTypeConverter, Devart.Data.Universal.Firebird"));
            descs.Add(new UniPropertyDescriptor("Connection Lifetime", "Pooling", "Connection lifetime", 
                typeof(System.Int32), 0));
            descs.Add(new UniPropertyDescriptor("Connection Timeout", "Advanced", 
                "The time (in seconds) to wait for a connection to open, 'Connect Timeout=X' in the ConnectionString.", typeof(System.Int32), 15));
            descs.Add(new UniPropertyDescriptor("Database", "Source", 
                "Current data source catalog value, 'Database=X' in the connection string", typeof(System.String), String.Empty));
            descs.Add(new UniPropertyDescriptor("Data Source", "Source", 
                "Current data source, 'Data Source=X' in the connection string", typeof(System.String), String.Empty));
            descs.Add(new UniPropertyDescriptor("Dialect", "Advanced", 
                "SQL dialect: an indicator that instructs a Firebird/InterBase server how to interpret the features whose meanings have changed between Firebird/InterBase versions", 
                typeof(System.Int32), null));
            descs.Add(new UniPropertyDescriptor("Fetch Size", "Advanced", "", typeof(System.Int32), null));
            descs.Add(new UniPropertyDescriptor("IsolationLevel", "Misc", "", typeof(System.Data.IsolationLevel), null));
            descs.Add(new UniPropertyDescriptor("Max Pool Size", "Pooling", 
                "The maximum number of connections allowed in the pool", typeof(System.Int32), 100));
            descs.Add(new UniPropertyDescriptor("Min Pool Size", "Pooling", 
                "The minimum number of connections allowed in the pool", typeof(System.Int32), 0));
            descs.Add(new UniPropertyDescriptor("Packet Size", "Advanced", 
                "Size in bytes of the network packets used to communicate with an instance of Firebird/Interbase server.", typeof(System.Int32), null));
            descs.Add(new UniPropertyDescriptor("User ID", "Security", "The name of user to connect.", typeof(System.String), String.Empty));
            descs.Add(new UniPropertyDescriptor("Password", "Security", "The user password.", typeof(System.String), String.Empty));
            descs.Add(new UniPropertyDescriptor("Persist Security Info", "Security", 
                "When false, security-sensitive information, like password, is not returned as a part of the connection if the connection is open or has ever been open.", 
                typeof(System.Boolean), false));
            descs.Add(new UniPropertyDescriptor("Pooling", "Pooling", 
                "When true, the connection object is drawn from the approptiate pool, or, if necessary, is created and added to the appropriate pool", 
                typeof(System.Boolean), true));
            descs.Add(new UniPropertyDescriptor("Port", "Source", 
                "The port of Firebird/Interbase database to which to connect, 'Port=X' in the ConnectionString.", typeof(System.Int32), 3050));
            descs.Add(new UniPropertyDescriptor("ReturnRecordsAffected", "Misc", "", typeof(System.Boolean), null));
            descs.Add(new UniPropertyDescriptor("Role", "Security", 
                "Specifies the role that the user adopts on connection to the database.", typeof(System.String), String.Empty));
            descs.Add(new UniPropertyDescriptor("ServerType", "Misc", "", typeof(FirebirdSql.Data.FirebirdClient.FbServerType), 
                FirebirdSql.Data.FirebirdClient.FbServerType.Default));
    
            connectionPropertyDescriptors = descs;
          }
    
          UniPropertyDescriptorCollection descriptors = new UniPropertyDescriptorCollection();
    
          foreach (UniPropertyDescriptor propertyDescriptor in connectionPropertyDescriptors) {
            descriptors.Add(propertyDescriptor);
          }
    
          return descriptors;
    
        }
    
        // synonyms for connection string parameters
        System.Collections.IDictionary IUniProvider.GetConnectionStringSynonyms() {
    
          Hashtable Synonyms = new Hashtable(StringComparer.InvariantCultureIgnoreCase);
          Synonyms.Add("User", "User Id");
          Synonyms.Add("Uid", "User Id");
          Synonyms.Add("pwd", "Password");
          Synonyms.Add("Host", "Data Source");
          Synonyms.Add("Server", "Data Source");
          Synonyms.Add("Connect timeout", "Connection Timeout");
    
          return Synonyms;
        }
        #endregion
      }
    
    
      #region FbCommandBuilderWrapper
      // IUniCommandBuilder wrapper is required, because UniDbCommandBuilder  uses
      // specific properties existing only in our providers, and absent in other ones.
      internal class FbCommandBuilderWrapper : IUniCommandBuilder {
    
        private FbCommandBuilder commandBuilder = new FbCommandBuilder();
        private CatalogLocation catalogLocation = CatalogLocation.Start;
    
        void IDisposable.Dispose() {
    
          commandBuilder.Dispose();
        }
    
        public IDbCommand GetInsertCommand() {
    
          return commandBuilder.GetInsertCommand();
        }
    
        public IDbCommand GetUpdateCommand() {
    
          return commandBuilder.GetUpdateCommand();
        }
    
        public IDbCommand GetDeleteCommand() {
    
          return commandBuilder.GetDeleteCommand();
        }
    
        public void RefreshSchema() {
    
          commandBuilder.RefreshSchema();
        }
    
        public IDbDataAdapter DataAdapter {
          get {
            return commandBuilder.DataAdapter;
          }
          set {
            commandBuilder.DataAdapter = (FbDataAdapter)value;
          }
        }
    
        public string QuotePrefix {
          get {
            return commandBuilder.QuotePrefix;
          }
          set {
            commandBuilder.QuotePrefix = value;
          }
        }
    
        public string QuoteSuffix {
          get {
            return commandBuilder.QuoteSuffix;
          }
          set {
            commandBuilder.QuoteSuffix = value;
          }
        }
    
        // Devart DbCommandBuilder specific properties
    
        public bool Quoted {
          get {
            return true;
          }
          set {
          }
        }
    
        public ConflictOption ConflictOption {
          get {
            return commandBuilder.ConflictOption;
          }
    
          set {
            commandBuilder.ConflictOption = value;
          }
        }
    
        protected string GetParameterName(int parameterOrdinal) {
    
          return "@p" + parameterOrdinal.ToString();
        }
    
        protected string GetParameterName(string parameterName) {
    
          if (parameterName.Length > 0 && parameterName[0] == '@') {
            return parameterName;
          }
          else {
            return "@" + parameterName;
          }
        }
    
        protected string GetParameterPlaceholder(int parameterOrdinal) {
    
          return "@p" + parameterOrdinal.ToString();
        }
    
        public string UpdatingTable {
          get {
            return String.Empty;
          }
          set {
          }
        }
    
        public string UpdatingFields {
          get {
            return String.Empty;
          }
          set {
          }
        }
    
        public string RefreshingFields {
          get {
            return String.Empty;
          }
          set {
          }
        }
    
        public RefreshRowMode RefreshMode {
          get {
            return RefreshRowMode.None;
          }
          set {
          }
        }
    
        public CatalogLocation CatalogLocation {
          get {
            return catalogLocation;
          }
          set {
            catalogLocation = value;
          }
        }
    
        public bool UseSchema {
          get {
            return true;
          }
          set {
          }
        }
    
        public bool UseCatalog {
          get {
            return true;
          }
          set {
          }
        }
      }
    
      #endregion
    
      #region FirebirdTypeMapping
      // example of possible mapping implementation, used for correct conversion of 
      // Uni - NativeProvider parameters
      // this class is used in methods SetNativeDbType and GetUniDbType
      internal class FirebirdTypeMapping {
    
        private static Hashtable uniType = null;
        private static Hashtable specType = null;
    
        static FirebirdTypeMapping() {
    
          uniType = new Hashtable(50);
          specType = new Hashtable(50);
    
          AssignNative(UniDbType.Decimal, FbDbType.Numeric);
          AssignNative(UniDbType.VarChar, FbDbType.VarChar);
          AssignNative(UniDbType.Char, FbDbType.Char);
          AssignNative(UniDbType.Binary, FbDbType.Binary);
          AssignNative(UniDbType.Binary, FbDbType.Binary);
          AssignNative(UniDbType.Boolean, FbDbType.Boolean);
          AssignNative(UniDbType.Byte, FbDbType.SmallInt, false);
          AssignNative(UniDbType.Currency, FbDbType.Decimal, false);
          AssignNative(UniDbType.Date, FbDbType.Date, false);
          AssignNative(UniDbType.DateTime, FbDbType.Date);
          AssignNative(UniDbType.Decimal, FbDbType.Decimal);
          AssignNative(UniDbType.Double, FbDbType.Double);
          AssignNative(UniDbType.Guid, FbDbType.Guid);
          AssignNative(UniDbType.SmallInt, FbDbType.SmallInt);
          AssignNative(UniDbType.Int, FbDbType.Integer);
          AssignNative(UniDbType.BigInt, FbDbType.BigInt);
          AssignNative(UniDbType.TinyInt, FbDbType.SmallInt, false);
          AssignNative(UniDbType.Single, FbDbType.Float);
          AssignNative(UniDbType.NVarChar, FbDbType.VarChar, false);
          AssignNative(UniDbType.NChar, FbDbType.Char, false);
          AssignNative(UniDbType.Time, FbDbType.Time);
          AssignNative(UniDbType.Xml, FbDbType.VarChar, false);
          AssignNative(UniDbType.TimeStamp, FbDbType.TimeStamp);
          AssignNative(UniDbType.IntervalDS, FbDbType.Time, false);
          AssignNative(UniDbType.IntervalYM, FbDbType.Date, false);
          AssignNative(UniDbType.DateTime2, FbDbType.TimeStamp, false);
          AssignNative(UniDbType.Blob, FbDbType.Binary, false);
          AssignNative(UniDbType.Clob, FbDbType.Text);
          AssignNative(UniDbType.NClob, FbDbType.Text, false);
          AssignNative(UniDbType.Array, FbDbType.Array);
          AssignNative(UniDbType.Bit, FbDbType.SmallInt, false);
        }
    
        static void AssignNative(UniDbType uniDbType, FbDbType nativeType) {
    
          AssignNative(uniDbType, nativeType, true);
        }
    
        static void AssignNative(UniDbType uniDbType, FbDbType nativeType, bool isDefault) {
    
          uniType[(int)uniDbType] = nativeType;
    
          if (isDefault) {
            specType[nativeType] = (int)uniDbType;
          }
        }
    
        public static UniDbType GetUniDbType(FbDbType nativeType) {
    
          if (specType.ContainsKey((int)nativeType))
            return (UniDbType)specType[(int)nativeType];
          else
            throw new ArgumentException(string.Format("{0} data type is not supported by dotConnect Universal", nativeType.ToString()));
        }
    
        public static FbDbType GetSpecificType(UniDbType uniDbType) {
    
          if (uniType.ContainsKey((int)uniDbType))
            return (FbDbType)uniType[(int)uniDbType];
          else
            throw new ArgumentException(string.Format("{0} data type id not supported by Firebird Data Provider", uniDbType.ToString()));
        }
      }
    
      #endregion
    
    }
    
    

    And here is how you can use this provider:

    using Devart.Data.Universal;
    using FirebirdSql.Data.FirebirdClient;
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace ConsoleApplication1 {
    
      class Program {
    
        static void Main(string[] args) {
     
          ProviderManager.Register(new MyFirebirdProvider());
    
          using (UniConnection connection = new UniConnection(
            "Provider=MyFirebirdClient;user id=SYSDBA;password=masterkey;Database=\"C:\\Program Files\\Firebird\\Firebird_3_0\\examples\\empbuild\\EMPLOYEE.FDB\";ServerType=0")) {
            connection.Open();
            UniCommand cmd = new UniCommand("SELECT * FROM EMPLOYEE", connection);
    
            using (UniDataReader rd = cmd.ExecuteReader()) {
              while (rd.Read()) {
                for (int i = 0; i < rd.FieldCount; i++)
                  Console.WriteLine("{0} = {1}", rd.GetName(i), rd.GetValue(i));
              }
              Console.WriteLine("---------------------------------");
            }
    
          }
    
          Console.WriteLine("Finish");
          Console.ReadKey();
        }
      }
    }