using System; using System.Data.Common; using System.Data.OleDb; using System.Transactions; namespace System.Data.Jet { public class JetConnection : DbConnection, IDisposable, ICloneable { // The SQL statement // // (SELECT COUNT(*) FROM MSysRelationships) // // is a DUAL table simulation in Access databases // It must be a single line table. // If user cannot gain access to MSysRelationships table he can create a table with 1 record // and change DUAL static property. // I.e. create table dual with one and only one record // // CREATE TABLE Dual (id COUNTER CONSTRAINT pkey PRIMARY KEY) // INSERT INTO Dual (id) VALUES (1) // ALTER TABLE Dual ADD CONSTRAINT DualTableConstraint CHECK ((SELECT Count(*) FROM Dual) = 1) // // then change the DUAL property // // JetConnection.DUAL = "Dual"; // // For more information see also https://en.wikipedia.org/wiki/DUAL_table /// /// The DUAL table or query /// public static string DUAL = DUALForAccdb; /// /// The dual table for accdb /// public const string DUALForMdb = "(SELECT COUNT(*) FROM MSysRelationships)"; /// /// The dual table for accdb /// public const string DUALForAccdb = "(SELECT COUNT(*) FROM MSysAccessStorage)"; /// /// Gets or sets a value indicating whether append random number for foreign key names. /// /// /// true if append random number for foreign key names; otherwise, false. /// public static bool AppendRandomNumberForForeignKeyNames = true; public static DateTime TimeSpanOffset = new DateTime(1899, 12, 30); /// /// Gets or sets a value indicating whether show SQL statements. /// /// /// true to show SQL statements; otherwise, false. /// static public bool ShowSqlStatements = false; /// /// Gets or sets a value indicating whether SQL statements should be indented /// /// /// true to indent SQL statements; otherwise, false. /// static public bool IndentSqlStatements = true; private static object _integerNullValue = int.MinValue; /// /// Gets or sets the integer null value returned by queries. This should solve a Jet issue /// that if I do a UNION ALL of null, int and null the Jet raises an error /// /// /// The integer null value. /// public static object IntegerNullValue { get { return _integerNullValue; } set { if (!(value is int) && value != null) throw new ArgumentOutOfRangeException("value", "IntegerNullValue should be an int or null"); _integerNullValue = value; } } internal DbConnection WrappedConnection { get; private set; } /// /// Initializes a new instance of the class. /// public JetConnection() { WrappedConnection = new OleDbConnection(); WrappedConnection.StateChange += WrappedConnection_StateChange; } /// /// Initializes a new instance of the class. /// /// The underling OleDb connection. public JetConnection(OleDbConnection connection) { WrappedConnection = connection; WrappedConnection.StateChange += WrappedConnection_StateChange; } /// /// Initializes a new instance of the class. /// /// The connection string. public JetConnection(string connectionString) : this() { this.ConnectionString = connectionString; } /// /// Gets the for this . /// protected override DbProviderFactory DbProviderFactory { get { return JetProviderFactory.Instance; } } /// /// Starts a database transaction. /// /// Specifies the isolation level for the transaction. /// /// An object representing the new transaction. /// protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) { switch (isolationLevel) { case IsolationLevel.Serializable: return new JetTransaction(WrappedConnection.BeginTransaction(IsolationLevel.ReadCommitted), this); case IsolationLevel.Chaos: case IsolationLevel.ReadCommitted: case IsolationLevel.ReadUncommitted: case IsolationLevel.RepeatableRead: case IsolationLevel.Snapshot: case IsolationLevel.Unspecified: default: return new JetTransaction(WrappedConnection.BeginTransaction(isolationLevel), this); } } /// /// Changes the current database for an open connection. /// /// Specifies the name of the database for the connection to use. public override void ChangeDatabase(string databaseName) { this.WrappedConnection.ChangeDatabase(databaseName); } /// /// Closes the connection to the database. This is the preferred method of closing any open connection. /// public override void Close() { this.WrappedConnection.Close(); } /// /// Gets or sets the string used to open the connection. /// public override string ConnectionString { get { return this.WrappedConnection.ConnectionString; } set { this.WrappedConnection.ConnectionString = value; } } /// /// Gets the time to wait while establishing a connection before terminating the attempt and generating an error. /// public override int ConnectionTimeout { get { return this.WrappedConnection.ConnectionTimeout; } } /// /// Creates and returns a object associated with the current connection. /// /// /// A object. /// protected override DbCommand CreateDbCommand() { DbCommand command = JetProviderFactory.Instance.CreateCommand(); command.Connection = this; return command; } /// /// Gets the name of the current database after a connection is opened, or the database name specified in the connection string before the connection is opened. /// public override string Database { get { return this.WrappedConnection.Database; } } /// /// Gets the name of the database server to which to connect. /// public override string DataSource { get { return this.WrappedConnection.DataSource; } } /// /// Releases the unmanaged resources used by the and optionally releases the managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { if (disposing) this.WrappedConnection.Dispose(); base.Dispose(disposing); OnDisposed(EventArgs.Empty); } /// /// Enlists in the specified transaction. /// /// A reference to an existing in which to enlist. public override void EnlistTransaction(Transaction transaction) { this.WrappedConnection.EnlistTransaction(transaction); } /// /// Returns schema information for the data source of this using the specified string for the schema name. /// /// Specifies the name of the schema to return. /// /// A that contains schema information. /// /// /// /// public override DataTable GetSchema(string collectionName) { return this.WrappedConnection.GetSchema(collectionName); } /// /// Returns schema information for the data source of this . /// /// /// A that contains schema information. /// /// /// /// public override DataTable GetSchema() { return this.WrappedConnection.GetSchema(); } /// /// Returns schema information for the data source of this using the specified string for the schema name and the specified string array for the restriction values. /// /// Specifies the name of the schema to return. /// Specifies a set of restriction values for the requested schema. /// /// A that contains schema information. /// /// /// /// public override DataTable GetSchema(string collectionName, string[] restrictionValues) { return this.WrappedConnection.GetSchema(collectionName, restrictionValues); } /// /// Opens a database connection with the settings specified by the . /// public override void Open() { this.WrappedConnection.Open(); } /// /// Gets a string that represents the version of the server to which the object is connected. /// public override string ServerVersion { get { return this.WrappedConnection.ServerVersion; } } /// /// Gets or sets the of the . /// public override System.ComponentModel.ISite Site { get { return this.WrappedConnection.Site; } set { this.WrappedConnection.Site = value; } } /// /// Gets a string that describes the state of the connection. /// public override ConnectionState State { get { return this.WrappedConnection.State; } } void WrappedConnection_StateChange(object sender, StateChangeEventArgs e) { OnStateChange(e); } public bool TableExists(string tableName) { ConnectionState oldConnectionState = State; bool tableExists; if (oldConnectionState == ConnectionState.Closed) Open(); try { string sqlFormat = "select count(*) from [{0}] where 1=2"; CreateCommand(string.Format(sqlFormat, tableName)).ExecuteNonQuery(); tableExists = true; } catch { tableExists = false; } if (oldConnectionState == ConnectionState.Closed) Close(); return tableExists; } public DbCommand CreateCommand(string commandText, int? commandTimeout = null) { if (string.IsNullOrEmpty(commandText)) // SqlCommand will complain if the command text is empty commandText = Environment.NewLine; var command = new JetCommand(commandText, this); if (commandTimeout.HasValue) command.CommandTimeout = commandTimeout.Value; return command; } /// /// Occurs when the component is disposed by a call to the method. /// public new event EventHandler Disposed; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnDisposed(EventArgs e) { if (Disposed != null) Disposed(this, e); } /// /// Creates a new object that is a copy of the current instance. /// /// /// A new object that is a copy of this instance. /// object ICloneable.Clone() { JetConnection clone = new JetConnection(); clone.WrappedConnection = (DbConnection)((ICloneable)this.WrappedConnection).Clone(); return clone; } /// /// Performs an explicit conversion from to . /// /// The connection. /// /// The result of the conversion. /// public static explicit operator OleDbConnection(JetConnection connection) { return (OleDbConnection)connection.WrappedConnection; } /// /// Clears the pool. /// /// The connection. public static void ClearPool(JetConnection connection) { // Actually Jet does not support pools } /// /// Clears all pools. /// public static void ClearAllPools() { // Actually Jet does not support pools } } }